Odoo10開發(fā)教程八(向?qū)c國際化)

向?qū)?/h4>

向?qū)б詣討B(tài)形式描述與用戶(或?qū)υ捒颍┑慕换ナ綍?。向?qū)c其他的模型不同,其基類是TransientModel而不是常見的ModelTransientModel類擴展自Model,并使用了其所有機制,具有以下特殊性:

  • 向?qū)в涗洸皇怯谰眯缘?,會在一段時間后自動從數(shù)據(jù)庫中刪除。這就是為什么他們被稱為瞬態(tài)。
  • 向?qū)P筒恍枰L問權(quán)限:用戶擁有向?qū)в涗浀乃袡?quán)限
  • 向?qū)в涗浛梢酝ㄟ^many2one字段引用普通記錄或向?qū)в涗?,但普通記錄無法通過many2one引用向?qū)в涗洝?br> 我們要創(chuàng)建一個向?qū)?,用來讓用戶可以生成授課的參與者,或者一次創(chuàng)建一個授課列表。

練習定義向?qū)?br> 創(chuàng)建一個向?qū)P?,這個向?qū)P屯ㄟ^many2one關(guān)聯(lián)授課模型,并通過many2many關(guān)聯(lián)合作伙伴模型。添加新文件openacademy/wizard.py

openacademy/__init__.py

from . import controllers
from . import models
from . import partner
from . import wizard

openacademy/wizard.py

# -*- coding: utf-8 -*-

from odoo import models, fields, api

class Wizard(models.TransientModel):
    _name = 'openacademy.wizard'

    session_id = fields.Many2one('openacademy.session',
        string="Session", required=True)
    attendee_ids = fields.Many2many('res.partner', string="Attendees")

啟動向?qū)?/h5>

向?qū)ㄟ^ir.actions.act_window記錄來啟動,target字段設(shè)置值為new。后者將在一個彈出窗口中打開向?qū)?。操作可以有菜單項觸發(fā)。還有另外一種方式來啟動向?qū)В菏褂妙愃朴谏厦娴?code>ir.actions.act_window記錄,但有一個額外字段src_model,指定那個模型的操作可用。該向?qū)⒊霈F(xiàn)在模型主視圖的上下文操作中。因為這是在ORM中的內(nèi)部鉤子,所以這個操作通過在XML文件的act_window標簽中進行定義。

<act_window id="launch_the_wizard"
            name="Launch the Wizard"
            src_model="context.model.name"
            res_model="wizard.model.name"
            view_mode="form"
            target="new"
            key2="client_action_multi"/>

向?qū)褂贸R?guī)視圖并且它的按鈕可以使用special="cancel"來關(guān)閉向?qū)Т翱诙恍枰3帧?/p>

練習啟動向?qū)?/p>

  1. 為向?qū)Фx一個form視圖
  2. 在授課模型的上下文中添加action用于啟動向?qū)?/li>
  3. 給向?qū)У?em>session字段定義默認值;使用上下文參數(shù)self._context來獲取當前授課

openacademy/wizard.py

class Wizard(models.TransientModel):
    _name = 'openacademy.wizard'

    def _default_session(self):
        return self.env['openacademy.session'].browse(self._context.get('active_id'))

    session_id = fields.Many2one('openacademy.session',
        string="Session", required=True, default=_default_session)
    attendee_ids = fields.Many2many('res.partner', string="Attendees")

openacademy/views/openacademy.xml

                  parent="openacademy_menu"
                  action="session_list_action"/>

        <record model="ir.ui.view" id="wizard_form_view">
            <field name="name">wizard.form</field>
            <field name="model">openacademy.wizard</field>
            <field name="arch" type="xml">
                <form string="Add Attendees">
                    <group>
                        <field name="session_id"/>
                        <field name="attendee_ids"/>
                    </group>
                </form>
            </field>
        </record>

        <act_window id="launch_session_wizard"
                    name="Add Attendees"
                    src_model="openacademy.session"
                    res_model="openacademy.wizard"
                    view_mode="form"
                    target="new"
                    key2="client_action_multi"/>
    </data>
</odoo>

練習注冊與會者
給向?qū)砑影粹o,并且實現(xiàn)相應的方法,將與會者添加到給定的授課。

openacademy / views / openacademy.xml

                        <field name="attendee_ids"/>
                    </group>
                    <footer>
                        <button name="subscribe" type="object"
                                string="Subscribe" class="oe_highlight"/>
                        or
                        <button special="cancel" string="Cancel"/>
                    </footer>
                </form>
            </field>
        </record>

openacademy/wizard.py

    session_id = fields.Many2one('openacademy.session',
        string="Session", required=True, default=_default_session)
    attendee_ids = fields.Many2many('res.partner', string="Attendees")

    @api.multi
    def subscribe(self):
        self.session_id.attendee_ids |= self.attendee_ids
        return {}

練習與會者注冊多個授課
修改向?qū)P?,以便與會者可以注冊到多個授課

openacademy/views/openacademy.xml

                <form string="Add Attendees">
                    <group>
                        <field name="session_ids"/>
                        <field name="attendee_ids"/>
                    </group>
                    <footer>
                        <button name="subscribe" type="object"

openacademy/wizard.py

class Wizard(models.TransientModel):
    _name = 'openacademy.wizard'

    def _default_sessions(self):
        return self.env['openacademy.session'].browse(self._context.get('active_ids'))

    session_ids = fields.Many2many('openacademy.session',
        string="Sessions", required=True, default=_default_sessions)
    attendee_ids = fields.Many2many('res.partner', string="Attendees")

    @api.multi
    def subscribe(self):
        for session in self.session_ids:
            session.attendee_ids |= self.attendee_ids
        return {}

國際化

每個模塊都可以在i18n目錄提供自己的翻譯,文件名的形式為LANG.po,其中LANG是語言的代碼,或者是語言和國家的組合,例如:pt.po(葡萄牙語)和pt_BR.po(巴西葡萄牙語)。對于所有開啟的語言,Odoo都會自動載入翻譯。開發(fā)者總是使用英語建立模塊,然后使用Odoo的文本POT導出功能導出模塊術(shù)語(設(shè)置->翻譯->導入/導出->導出翻譯),生成模塊的POT模板文件,然后到處PO翻譯文件。許多IDE具有用于編輯和合并PO/POT文件的插件或功能。

提示
把Odoo生成的導出文件公布在Transifex,可以輕松的使用軟件進行翻譯。

|- idea/ # The module directory
   |- i18n/ # Translation files
      | - idea.pot # Translation Template (exported from Odoo)
      | - fr.po # French translation
      | - pt_BR.po # Brazilian Portuguese translation
      | (...)

提示
默認情況下Odoo的POT導出僅提取XML文件的標簽和Python代碼中的字段定義,但是任何Python字符串都可以翻譯,通過使用odoo._()方法,例如_("Label")。


練習
翻譯一個模塊
為已經(jīng)安裝的Odoo模塊選擇第二語言。使用Odoo提供的功能對模塊進行翻譯。

  1. 創(chuàng)建目錄openacademy/i18n/
  2. 安裝任意一種你希望的語言 (設(shè)置->翻譯->加載翻譯
  3. 同步翻譯術(shù)語(設(shè)置->翻譯->應用程序術(shù)語->同步術(shù)語
  4. 導出不指定語言的翻譯模板文件(設(shè)置->翻譯->導入/導出->導出翻譯),保存在openacademy/i18n/
  5. 導出指定語言的翻譯文件(設(shè)置->翻譯->導入/導出->導出翻譯),保存在openacademy/i18n/
  6. 打開導出的翻譯文件(使用任意一款文本編輯軟件或者專用的PO文件編輯器,例如POEdit然后翻譯其中的術(shù)語)
  7. models.py文件中,為odoo._方法添加一個導入聲明,并且標記需要翻譯的字符串
  8. 重復3-6的步驟

openacademy/models.py

# -*- coding: utf-8 -*-

from datetime import timedelta
from odoo import models, fields, api, exceptions, _

class Course(models.Model):
    _name = 'openacademy.course'
        default = dict(default or {})

        copied_count = self.search_count(
            [('name', '=like', _(u"Copy of {}%").format(self.name))])
        if not copied_count:
            new_name = _(u"Copy of {}").format(self.name)
        else:
            new_name = _(u"Copy of {} ({})").format(self.name, copied_count)

        default['name'] = new_name
        return super(Course, self).copy(default)
        if self.seats < 0:
            return {
                'warning': {
                    'title': _("Incorrect 'seats' value"),
                    'message': _("The number of available seats may not be negative"),
                },
            }
        if self.seats < len(self.attendee_ids):
            return {
                'warning': {
                    'title': _("Too many attendees"),
                    'message': _("Increase seats or remove excess attendees"),
                },
            }
    def _check_instructor_not_in_attendees(self):
        for r in self:
            if r.instructor_id and r.instructor_id in r.attendee_ids:
                raise exceptions.ValidationError(_("A session's instructor can't be an attendee"))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容