Reputation: 438
I am using xmlrpc to add translation for some fields in my website. I used a function to do this (update_translation). I successfully translated names of the products, and names of categories. But when I try to add translation for website description, I am facing this error -> 'str' object has no attribute 'get'.
import xmlrpc.client
def update_translation(auth_info, view_name, prod_id, field2update, translations):
"""This method is used for updating translation for fields in odoo16
Args:
auth_info (dict): dictionary of authentication info
view_name (str): name of the table, example: product.template
prod_id (int): id of the record to which we change translations
field2update (str): name of the field to translate
translations (dict): dict of translation'
{'ar_001': 'translated string in arabic'}
or
{'en_US': 'Enlgish string',
'ar_001': 'translated string in arabic'}
Returns: 0
"""
common = xmlrpc.client.ServerProxy(f"{auth_info['url']}/xmlrpc/2/common")
models = xmlrpc.client.ServerProxy(f"{auth_info['url']}/xmlrpc/2/object")
version_of_odoo_instance = common.version()
uid = common.authenticate(auth_info['db'], auth_info['username'],
auth_info['password'], version_of_odoo_instance)
models.execute_kw(auth_info['db'], uid,
auth_info['password'], view_name,
'update_field_translations',
[[prod_id], field2update, translations])
return 0
# authentication info for the function.
server_1 = {
'url': "http://mywebsiteip:8069/",
'db': "database_name", # name of database 1
'username': "myusername",
'password': "mypassword*"
}
# in the case of both product name and category name, input data was a
# simple string. For website description I am using an html file.
# for each product I have two html files. One for English and One for Arabic.
html_web_descr = {}
# load English translaton to dictionary
html_path = 'fullpath/myfile_en.html'
with open(html_path, 'r', encoding='utf-8-sig') as f:
data = f.read()
html_web_descr['en_US'] = data
# load arabic translaton to dictionary
html_path = 'fullpath/myfile_ar.html'
with open(html_path, 'r', encoding='utf-8-sig') as f:
data = f.read()
html_web_descr['ar_001'] = data
product_id = 652
# (auth_info, view_name, prod_id, field2update, translations)
update_translation(server_1, 'product.template', product_id, 'website_description', html_web_descr)
A sample of html file will be like this:
<div>
<div>
<h2>Product Description</h2>
<div class="accordion-body">
<p>Lot of text here followed by a break<br></p>
</div>
</div>
<div>
<h2>Product Features</h2>
<div class="accordion-body">
<p>Lot of text here followed by a break<br></p>
</div>
</div>
<div>
<h2>How to use</h2>
<div class="accordion-body">
<p>Lot of text here followed by a break<br></p>
</div>
</div>
</div>
Trace back of the error:
<Fault 1: 'Traceback (most recent call last):\n
File "/opt/odoo/odoo-server/odoo/addons/base/controllers/rpc.py", line 148, in xmlrpc_2\n response = self._xmlrpc(service)\n
File "/opt/odoo/odoo-server/odoo/addons/base/controllers/rpc.py", line 128, in _xmlrpc\n result = dispatch_rpc(service, method, params)\n
File "/opt/odoo/odoo-server/odoo/http.py", line 368, in dispatch_rpc\n return dispatch(method, params)\n
File "/opt/odoo/odoo-server/odoo/service/model.py", line 37, in dispatch\n res = execute_kw(db, uid, *params[3:])\n
File "/opt/odoo/odoo-server/odoo/service/model.py", line 59, in execute_kw\n return execute(db, uid, obj, method, *args, **kw or {})\n
File "/opt/odoo/odoo-server/odoo/service/model.py", line 65, in execute\n res = execute_cr(cr, uid, obj, method, *args, **kw)\n
File "/opt/odoo/odoo-server/odoo/service/model.py", line 50, in execute_cr\n result = retrying(partial(odoo.api.call_kw, recs, method, args, kw), env)\n
File "/opt/odoo/odoo-server/odoo/service/model.py", line 134, in retrying\n result = func()\n
File "/opt/odoo/odoo-server/odoo/api.py", line 461, in call_kw\n result = _call_kw_multi(method, model, args, kwargs)\n
File "/opt/odoo/odoo-server/odoo/api.py", line 448, in _call_kw_multi\n result = method(recs, *args, **kwargs)\n
File "/opt/odoo/odoo-server/odoo/models.py", line 2987, in update_field_translations\n return self._update_field_translations(field_name, translations)\n
File "/opt/odoo/odoo-server/odoo/models.py", line 3075, in _update_field_translations\n new_translations[lang] = field.translate(translation.get, old_value)\nAttributeError: \'str\' object has no attribute \'get\'\n'>
The function is working fine for name field. So I made sure that website description field also have the same property Translatable:True. Issue happens only through xmlrpc. I can translate the field manually through GUI. Which is not ideal considering I have 1000+ products. Is my approach wrong? How can I solve this?
I tried to read the source code of Odoo 16 to see why it happens it did not make sense to me, I am new to python. Line 2988 of model.py
Upvotes: 0
Views: 570
Reputation: 88
You need to split your input into parts based on html. From my testing, html will get devided into parts of text in the translation context. the division is done based on ,
tag etc.
so to update the tranlation through xmlrpc you need to follow these steps.
def update_data_in_db(auth_info, view_name, prod_id, dict_of_values_to_change): """This function will update existing data fields with new value
Args:
auth_info (dictionary): authentication info for server
view_name (str): view name for the model we are updating.
prod_id (int): ID of the product we are editing
dict_of_values_to_change (dict): a dict of values that needs to be updated
{'field_name': new_value}
"""
common = xmlrpc.client.ServerProxy(f"{auth_info['url']}/xmlrpc/2/common")
models = xmlrpc.client.ServerProxy(f"{auth_info['url']}/xmlrpc/2/object")
version_of_odoo_instance = common.version()
uid = common.authenticate(auth_info['db'], auth_info['username'],
auth_info['password'], version_of_odoo_instance)
models.execute_kw(auth_info['db'], uid,
auth_info['password'], view_name,
'write', [prod_id, dict_of_values_to_change])
return 0
while doing the above step, extract text form the html to get the parts for translation. from my observation, odoo cuts the text at tags and
tags. So you will endup with a list like this.
[Product Description, Lot of text here followed by a break
,Product Features, Lot of text here followed by a break
, How to use, Lot of text here followed by a break
]
extract the same from your arabic translaton. so that you will endup with lists of same size. Thus english text and arabic text have the same index id in their corresponding lists.
use zip to make a dictionary from the above lists. I named them english_text, and arabic_text. en_ar_dict = dict(zip(englist_text, arabic_text)) # you will endup with a dictionary like this ==> {'english txt1': 'arabic txt1', 'english txt2': 'arabic txt2'}
Now you can use the same function you used for translationg names. update_translation(server_1, 'product.template', product_id,'website_description', {'ar_001': en_ar_dict)
Upvotes: 0