Skip to content

Conversation

kmagusiak
Copy link
Contributor

@kmagusiak kmagusiak commented Jul 29, 2024

Python translations need to know the language and the module to find the translated term. Today's _ function must resolve both of these values from the current stack by using some heuristics.
These heuristics don't always work properly: to find the language we look in the caller's scope to find it in the context or to find the environment from which we can read lang.
For the module, if the function is used outside of an addon, we default to 'base'.

We add a function Environment._ for translations. That function uses its lang property for the language without resorting to inspecting the call stack. You can also pass the module, but we can still resolve it dynamically.

For lazy translations, we create a new LazyTranslate factory that you can use as _lt = LazyTranslate(__name__) in any addon. This will resolve the addon name once per file from the name of the package without going through inspect. You can then use Environment._ to get the translation or str() to resolve the lanugage dynamically.

odoo/enterprise#67528
odoo/documentation#10421
task-4034999


I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr

@robodoo
Copy link
Contributor

robodoo commented Jul 29, 2024

Pull request status dashboard

@C3POdoo C3POdoo added the RD research & development, internal work label Jul 29, 2024
@kmagusiak kmagusiak force-pushed the master-env-translate-obj-krma branch from b2471ba to b45ee0f Compare July 29, 2024 15:02
@kmagusiak kmagusiak force-pushed the master-env-translate-obj-krma branch from b45ee0f to 74e4d2f Compare July 29, 2024 15:54
@kmagusiak
Copy link
Contributor Author

kmagusiak commented Jul 29, 2024

Performance improvement

Translation

def test_(self):
    return _("some string")
def testenv(self):
    return self.env._("some string")
def testenvmod(self):
    return self.env._("some string", _mod='base')
self_fr = self.with_context(lang="fr_BE")

%timeit test_(self)
# before: 1.27 μs ± 14.3 ns per loop
# after: 1.4 μs ± 17.6 ns per loop
%timeit test_(self_fr)
# before: 11 μs ± 40.8 ns per loop
# after: 12.5  μs ± 157 ns per loop
%timeit testenv(self)
# 286 ns ± 1.52 ns per loop
%timeit testenv(self_fr)
# 11.4 μs ± 73.3 ns per loop
%timeit testenvmod(self)
# 290 ns ± 0.57 ns per loop
%timeit testenvmod(self_fr)
# 467 ns ± 1.02 ns per loop

There is one more function call and isinstance checks that add ~150ns to the original function.
The new API is about 4x faster if the language is "en_US" and the speed is similar when we need to dynamically find the module name. Note that finding the name is 20x slower than deducing it from the package name.

Lazy

# before
%timeit _lt("hello world")
# 45.3 μs ± 201 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

# after
%timeit lt = LazyTranslate('odoo.addons.test')
# 2.63 μs ± 27.3 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
%timeit lt("hello world")
# 4.05 μs ± 50 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

For 10 translations we go from 450μs to 43μs: 10x improvement.

@kmagusiak kmagusiak force-pushed the master-env-translate-obj-krma branch from 74e4d2f to 931a666 Compare July 29, 2024 19:37
@kmagusiak kmagusiak marked this pull request as ready for review July 29, 2024 19:37
@kmagusiak kmagusiak force-pushed the master-env-translate-obj-krma branch 2 times, most recently from 3d55405 to 03adb5c Compare July 30, 2024 09:28
@C3POdoo C3POdoo requested review from a team and aboo-odoo and removed request for a team July 30, 2024 10:20
moylop260 pushed a commit to vauxoo-dev/pylint-odoo that referenced this pull request Jan 13, 2025
@moylop260
Copy link
Contributor

Hi, the following lint detects all the old cases using _ method:

And there are a lot of occurrences:

My question is, what is the plan with all these sentences using the old way _?

I mean, it will be migrated to new self.env._ or _lt?

@kmagusiak
Copy link
Contributor Author

Hi, the following lint detects all the old cases using _ method:

And there are a lot of occurrences:

My question is, what is the plan with all these sentences using the old way _?

I mean, it will be migrated to new self.env._ or _lt?

Probably someday we will script that migration, but there are cases where it is not 100% equivalent; right now it is during review that people can prefer one over the other. The old _ function tries to find the language in multiple places and sometimes succeeds; for example if you have a global HTTP request even if you don't have an environment in the local scope of the function.

moylop260 pushed a commit to vauxoo-dev/pylint-odoo that referenced this pull request Jan 14, 2025
Related to odoo/odoo#174844

The new way to translate is using `self.env._()` instead of `_` method

But if there is not environment available in the code you can use LazyTranslate

```python
from odoo. tools import LazyTranslate
_lt = LazyTranslate(__name__)
```
moylop260 added a commit to OCA/pylint-odoo that referenced this pull request Jan 14, 2025
Related to odoo/odoo#174844

The new way to translate is using `self.env._()` instead of `_` method

But if there is not environment available in the code you can use LazyTranslate

```python
from odoo. tools import LazyTranslate
_lt = LazyTranslate(__name__)
```

Co-authored-by: trisdoan <doanminhtri8183@gmail.com>
IrvingReyes added a commit to vauxoo-dev/addons-vauxoo that referenced this pull request Feb 14, 2025
- The es.po translation file was updated.
- The check_access_rights method was updated to check_access. [1]
- The _filter_access_rules_python method was updated to _filtered_access. [2]
- String translation calls using _() were replaced with self.env._(). [3]
- Version numbers were updated from "17.0" to "18.0".
- Tree views were updated to list views in templates. [4]
- The field `is_editable` is removed from the picking form view, as
  invisible fields are no longer required due to [5].

[1]: odoo/odoo#179148
[2]: odoo/odoo#179148
[3]: odoo/odoo#174844
[4]: odoo/odoo#159909
[5]: odoo/odoo#137031
IrvingReyes added a commit to vauxoo-dev/addons-vauxoo that referenced this pull request Feb 17, 2025
- The es.po translation file was updated.
- The check_access_rights method was updated to check_access. [1]
- The _filter_access_rules_python method was updated to _filtered_access. [1]
- String translation calls using _() were replaced with self.env._(). [2]
- Version numbers were updated from "17.0" to "18.0".
- Tree views were updated to list views in templates. [3]
- The field `is_editable` is removed from the picking form view, as
  invisible fields are no longer required due to [4].

[1]: odoo/odoo#179148
[2]: odoo/odoo#174844
[3]: odoo/odoo#159909
[4]: odoo/odoo#137031
luisg123v pushed a commit to Vauxoo/addons-vauxoo that referenced this pull request Feb 17, 2025
- The es.po translation file was updated.
- The check_access_rights method was updated to check_access. [1]
- The _filter_access_rules_python method was updated to _filtered_access. [1]
- String translation calls using _() were replaced with self.env._(). [2]
- Version numbers were updated from "17.0" to "18.0".
- Tree views were updated to list views in templates. [3]
- The field `is_editable` is removed from the picking form view, as
  invisible fields are no longer required due to [4].

[1]: odoo/odoo#179148
[2]: odoo/odoo#174844
[3]: odoo/odoo#159909
[4]: odoo/odoo#137031
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
17.5 RD research & development, internal work
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants