Browse Source

Merge pull request #872 from Tecnativa/10.0-datetime_formatter

[MIG][10.0][datetime_formatter] Migration
pull/673/merge
Pedro M. Baeza 8 years ago
committed by GitHub
parent
commit
017b48f12d
  1. 72
      datetime_formatter/README.rst
  2. 5
      datetime_formatter/__init__.py
  3. 20
      datetime_formatter/__manifest__.py
  4. 30
      datetime_formatter/i18n/ar.po
  5. 30
      datetime_formatter/i18n/ca.po
  6. 30
      datetime_formatter/i18n/de.po
  7. 31
      datetime_formatter/i18n/es.po
  8. 30
      datetime_formatter/i18n/fr.po
  9. 30
      datetime_formatter/i18n/it.po
  10. 30
      datetime_formatter/i18n/sl.po
  11. 30
      datetime_formatter/i18n/tr.po
  12. 3
      datetime_formatter/models/__init__.py
  13. 123
      datetime_formatter/models/res_lang.py
  14. BIN
      datetime_formatter/static/description/icon.png
  15. 3
      datetime_formatter/tests/__init__.py
  16. 76
      datetime_formatter/tests/test_best_matcher.py
  17. 93
      datetime_formatter/tests/test_formatter.py

72
datetime_formatter/README.rst

@ -0,0 +1,72 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
=====================
Date & Time Formatter
=====================
This module was written to extend the functionality of Odoo language engine to
support formatting `Date`, `Time` and `Datetime` fields easily and allow you to
print them in the best format for the user.
Usage
=====
This module adds a technical programming feature, and it should be used by
addon developers, not by end users. This means that you must not expect to see
any changes if you are a user and install this, but if you find you have it
already installed, it's probably because you have another modules that depend
on this one.
If you are a developer, to use this module, you need to:
* Call anywhere in your code::
formatted_string = self.env["res.lang"].datetime_formatter(datetime_value)
* If you use Qweb::
<t t-esc="env['res.lang'].datetime_formatter(datetime_value)"/>
* If you call it from a record that has a `lang` field::
formatted_string = record.lang.datetime_formatter(record.datetime_field)
* ``models.ResLang.datetime_formatter`` docstring explains its usage.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/149/10.0
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/server-tools/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smashing it by providing a detailed and welcomed feedback.
Credits
=======
Contributors
------------
* Jairo Llopis <j.llopis@grupoesoc.es>
* Vicent Cubells <vicent.cubells@tecnativa.com>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.

5
datetime_formatter/__init__.py

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import models
# Make these easily available for submodules
from .models.res_lang import MODE_DATE, MODE_DATETIME, MODE_TIME

20
datetime_formatter/__manifest__.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Copyright 2015, 2017 Jairo Llopis <jairo.llopis@tecnativa.com>
# Copyright 2016 Tecnativa, S.L. - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
"name": "Date & Time Formatter",
"summary": "Helper functions to give correct format to date[time] fields",
"version": "10.0.1.0.0",
"category": "Tools",
"website": "https://www.tecnativa.com",
"author": "Grupo ESOC Ingeniería de Servicios, "
"Tecnativa,"
"Odoo Community Association (OCA)",
"license": "AGPL-3",
"installable": True,
"depends": [
"base",
],
}

30
datetime_formatter/i18n/ar.po

@ -0,0 +1,30 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * datetime_formatter
#
# Translators:
# new stargate <newstargate@gmail.com>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 9.0c\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-26 01:46+0000\n"
"PO-Revision-Date: 2016-11-26 01:46+0000\n"
"Last-Translator: new stargate <newstargate@gmail.com>, 2016\n"
"Language-Team: Arabic (https://www.transifex.com/oca/teams/23907/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: datetime_formatter
#: code:addons/datetime_formatter/exceptions.py:10
#, python-format
msgid "Best matched language (%s) not found."
msgstr ""
#. module: datetime_formatter
#: model:ir.model,name:datetime_formatter.model_res_lang
msgid "Languages"
msgstr "اللغات"

30
datetime_formatter/i18n/ca.po

@ -0,0 +1,30 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * datetime_formatter
#
# Translators:
# Marc Tormo i Bochaca <mtbochaca@gmail.com>, 2017
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 9.0c\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-04-19 18:00+0000\n"
"PO-Revision-Date: 2017-04-19 18:00+0000\n"
"Last-Translator: Marc Tormo i Bochaca <mtbochaca@gmail.com>, 2017\n"
"Language-Team: Catalan (https://www.transifex.com/oca/teams/23907/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: datetime_formatter
#: code:addons/datetime_formatter/exceptions.py:10
#, python-format
msgid "Best matched language (%s) not found."
msgstr "No s'ha trobat la millor associació d'idioma (%s). "
#. module: datetime_formatter
#: model:ir.model,name:datetime_formatter.model_res_lang
msgid "Languages"
msgstr "Idiomes "

30
datetime_formatter/i18n/de.po

@ -0,0 +1,30 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * datetime_formatter
#
# Translators:
# OCA Transbot <transbot@odoo-community.org>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 9.0c\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-26 01:46+0000\n"
"PO-Revision-Date: 2016-11-26 01:46+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2016\n"
"Language-Team: German (https://www.transifex.com/oca/teams/23907/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: datetime_formatter
#: code:addons/datetime_formatter/exceptions.py:10
#, python-format
msgid "Best matched language (%s) not found."
msgstr "Sprache (%s) mit bester Übereinstimmung nicht gefunden"
#. module: datetime_formatter
#: model:ir.model,name:datetime_formatter.model_res_lang
msgid "Languages"
msgstr "Sprachen"

31
datetime_formatter/i18n/es.po

@ -0,0 +1,31 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * datetime_formatter
#
# Translators:
# OCA Transbot <transbot@odoo-community.org>, 2016
# Pedro M. Baeza <pedro.baeza@gmail.com>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 9.0c\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-12-23 21:53+0000\n"
"PO-Revision-Date: 2016-12-23 21:53+0000\n"
"Last-Translator: Pedro M. Baeza <pedro.baeza@gmail.com>, 2016\n"
"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/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=2; plural=(n != 1);\n"
#. module: datetime_formatter
#: code:addons/datetime_formatter/exceptions.py:10
#, python-format
msgid "Best matched language (%s) not found."
msgstr "No se ha encontrado ningún idioma (%s) que mejor case."
#. module: datetime_formatter
#: model:ir.model,name:datetime_formatter.model_res_lang
msgid "Languages"
msgstr "Idiomas"

30
datetime_formatter/i18n/fr.po

@ -0,0 +1,30 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * datetime_formatter
#
# Translators:
# Christophe CHAUVET <christophe.chauvet@gmail.com>, 2016
msgid ""
msgstr ""
"Project-Id-Version: server-tools (8.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-08-21 06:45+0000\n"
"PO-Revision-Date: 2016-08-21 07:41+0000\n"
"Last-Translator: Christophe CHAUVET <christophe.chauvet@gmail.com>\n"
"Language-Team: French (http://www.transifex.com/oca/OCA-server-tools-8-0/language/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=2; plural=(n > 1);\n"
#. module: datetime_formatter
#: code:addons/datetime_formatter/exceptions.py:9
#, python-format
msgid "Best matched language (%s) not found."
msgstr ""
#. module: datetime_formatter
#: model:ir.model,name:datetime_formatter.model_res_lang
msgid "Languages"
msgstr "Langues"

30
datetime_formatter/i18n/it.po

@ -0,0 +1,30 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * datetime_formatter
#
# Translators:
# Paolo Valier, 2016
msgid ""
msgstr ""
"Project-Id-Version: server-tools (8.0)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-03-17 15:37+0000\n"
"PO-Revision-Date: 2016-03-13 09:34+0000\n"
"Last-Translator: Paolo Valier\n"
"Language-Team: Italian (http://www.transifex.com/oca/OCA-server-tools-8-0/language/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=2; plural=(n != 1);\n"
#. module: datetime_formatter
#: code:addons/datetime_formatter/exceptions.py:9
#, python-format
msgid "Best matched language (%s) not found."
msgstr ""
#. module: datetime_formatter
#: model:ir.model,name:datetime_formatter.model_res_lang
msgid "Languages"
msgstr "Lingue"

30
datetime_formatter/i18n/sl.po

@ -0,0 +1,30 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * datetime_formatter
#
# Translators:
# OCA Transbot <transbot@odoo-community.org>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 9.0c\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-26 01:46+0000\n"
"PO-Revision-Date: 2016-11-26 01:46+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2016\n"
"Language-Team: Slovenian (https://www.transifex.com/oca/teams/23907/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: datetime_formatter
#: code:addons/datetime_formatter/exceptions.py:10
#, python-format
msgid "Best matched language (%s) not found."
msgstr "Najbolj ujemajoč jezik (%s) ni najden."
#. module: datetime_formatter
#: model:ir.model,name:datetime_formatter.model_res_lang
msgid "Languages"
msgstr "Jeziki"

30
datetime_formatter/i18n/tr.po

@ -0,0 +1,30 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * datetime_formatter
#
# Translators:
# OCA Transbot <transbot@odoo-community.org>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 9.0c\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-11-26 01:46+0000\n"
"PO-Revision-Date: 2016-11-26 01:46+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2016\n"
"Language-Team: Turkish (https://www.transifex.com/oca/teams/23907/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: datetime_formatter
#: code:addons/datetime_formatter/exceptions.py:10
#, python-format
msgid "Best matched language (%s) not found."
msgstr "En iyi eşleşen dil (%s) bulunamadı."
#. module: datetime_formatter
#: model:ir.model,name:datetime_formatter.model_res_lang
msgid "Languages"
msgstr "Diller"

3
datetime_formatter/models/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import res_lang

123
datetime_formatter/models/res_lang.py

@ -0,0 +1,123 @@
# -*- coding: utf-8 -*-
# Copyright 2015, 2017 Jairo Llopis <jairo.llopis@tecnativa.com>
# Copyright 2016 Tecnativa, S.L. - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from datetime import datetime, timedelta
from odoo import _, api, fields, models
from odoo.tools import (DEFAULT_SERVER_DATE_FORMAT,
DEFAULT_SERVER_TIME_FORMAT)
from odoo.exceptions import UserError
# Available modes for :param:`.ResLang.datetime_formatter.template`
MODE_DATETIME = "MODE_DATETIME"
MODE_DATE = "MODE_DATE"
MODE_TIME = "MODE_TIME"
class ResLang(models.Model):
_inherit = "res.lang"
@api.model
@api.returns('self')
def best_match(self, lang=None, failure_safe=True):
"""Get best match of current default lang.
:param str lang:
If a language in the form of "en_US" is supplied, it will have the
highest priority.
:param bool failure_safe:
If ``False`` and the best matched language is not found installed,
an exception will be raised. Otherwise, the first installed
language found in the DB will be returned.
"""
# Find some installed language, as fallback
first_installed = self.search([("active", "=", True)], limit=1)
if not lang:
lang = (
# Object's language, if called like
# ``record.lang.datetime_formatter(datetime_obj)``
(self.ids and self[0].code) or
# Context language
self.env.context.get("lang") or
# User's language
self.env.user.lang or
# First installed language found
first_installed.code)
# Get DB lang record
record = self.search([("code", "=", lang)])
try:
record.ensure_one()
except ValueError:
if not failure_safe:
raise UserError(
_("Best matched language (%s) not found.") % lang
)
else:
record = first_installed
return record
@api.model
def datetime_formatter(self, value, lang=None, template=MODE_DATETIME,
separator=" ", failure_safe=True):
"""Convert a datetime field to lang's default format.
:type value: `str`, `float` or `datetime.datetime`
:param value:
Datetime that will be formatted to the user's preferred format.
:param str lang:
See :param:`lang` from :meth:`~.best_match`.
:param bool failure_safe:
See :param:`failure_safe` from :meth:`~.best_match`.
:param str template:
Will be used to format :param:`value`. If it is one of the special
constants :const:`MODE_DATETIME`, :const:`MODE_DATE` or
:const:`MODE_TIME`, it will use the :param:`lang`'s default
template for that mode.
:param str separator:
Only used when :param:`template` is :const:`MODE_DATETIME`, as the
separator between the date and time parts.
"""
# Get the correct lang
lang = self.best_match(lang)
# Get the template
if template in {MODE_DATETIME, MODE_DATE, MODE_TIME}:
defaults = []
if "DATE" in template:
defaults.append(lang.date_format or
DEFAULT_SERVER_DATE_FORMAT)
if "TIME" in template:
defaults.append(lang.time_format or
DEFAULT_SERVER_TIME_FORMAT)
template = separator.join(defaults)
# Convert str to datetime objects
if isinstance(value, (str, unicode)):
try:
value = fields.Datetime.from_string(value)
except ValueError:
# Probably failed due to value being only time
value = datetime.strptime(value, DEFAULT_SERVER_TIME_FORMAT)
# Time-only fields are floats for Odoo
elif isinstance(value, float):
# Patch values >= 24 hours
if value >= 24:
template = template.replace("%H", "%d" % value)
# Convert to time
value = (datetime.min + timedelta(hours=value)).time()
return value.strftime(template)

BIN
datetime_formatter/static/description/icon.png

After

Width: 128  |  Height: 128  |  Size: 9.2 KiB

3
datetime_formatter/tests/__init__.py

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import test_best_matcher, test_formatter

76
datetime_formatter/tests/test_best_matcher.py

@ -0,0 +1,76 @@
# -*- coding: utf-8 -*-
# Copyright 2015, 2017 Jairo Llopis <jairo.llopis@tecnativa.com>
# Copyright 2016 Tecnativa, S.L. - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo.tests.common import TransactionCase
from odoo.exceptions import UserError
class BasicCase(TransactionCase):
def setUp(self):
super(BasicCase, self).setUp()
self.langs = ("en_US", "es_ES", "it_IT", "pt_PT", "zh_CN")
self.rl = self.env["res.lang"]
for lang in self.langs:
if not self.rl.search([("code", "=", lang)]):
self.rl.load_lang(lang)
def test_explicit(self):
"""When an explicit lang is used."""
for lang in self.langs:
self.assertEqual(self.rl.best_match(lang).code, lang)
def test_record(self):
"""When called from a ``res.lang`` record."""
rl = self.rl.with_context(lang="it_IT")
rl.env.user.lang = "pt_PT"
for lang in self.langs:
self.assertEqual(
rl.search([("code", "=", lang)]).best_match().code,
lang)
def test_context(self):
"""When called with a lang in context."""
self.env.user.lang = "pt_PT"
for lang in self.langs:
self.assertEqual(
self.rl.with_context(lang=lang).best_match().code,
lang)
def test_user(self):
"""When lang not specified in context."""
for lang in self.langs:
self.env.user.lang = lang
# Lang is False in context
self.assertEqual(
self.rl.with_context(lang=False).best_match().code,
lang)
# Lang not found in context
self.assertEqual(
self.rl.with_context(dict()).best_match().code,
lang)
def test_first_installed(self):
"""When falling back to first installed language."""
first = self.rl.search([("active", "=", True)], limit=1)
self.env.user.lang = False
self.assertEqual(
self.rl.with_context(lang=False).best_match().code,
first.code)
def test_unavailable(self):
"""When matches to an unavailable language."""
self.env.user.lang = False
self.rl = self.rl.with_context(lang=False)
first = self.rl.search([("active", "=", True)], limit=1)
# Safe mode
self.assertEqual(self.rl.best_match("fake_LANG").code, first.code)
# Unsafe mode
with self.assertRaises(UserError):
self.rl.best_match("fake_LANG", failure_safe=False)

93
datetime_formatter/tests/test_formatter.py

@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-
# Copyright 2015, 2017 Jairo Llopis <jairo.llopis@tecnativa.com>
# Copyright 2016 Tecnativa, S.L. - Vicent Cubells
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import datetime
from random import random
from odoo.tests.common import TransactionCase
from odoo.tools import (DEFAULT_SERVER_DATE_FORMAT,
DEFAULT_SERVER_TIME_FORMAT,
DEFAULT_SERVER_DATETIME_FORMAT)
from ..models.res_lang import MODE_DATE, MODE_TIME, MODE_DATETIME
class FormatterCase(TransactionCase):
def setUp(self):
super(FormatterCase, self).setUp()
self.rl = self.env["res.lang"]
self.bm = self.rl.best_match()
self.dt = datetime.datetime.now()
self.d_fmt = self.bm.date_format or DEFAULT_SERVER_DATE_FORMAT
self.t_fmt = self.bm.time_format or DEFAULT_SERVER_TIME_FORMAT
self.kwargs = dict()
def tearDown(self):
# This should be returned
self.expected = self.dt.strftime(self.format)
# Pass a datetime object
self.assertEqual(
self.expected,
self.rl.datetime_formatter(
self.dt,
**self.kwargs))
# When the date comes as a string
if isinstance(self.dt, datetime.datetime):
self.dt_str = self.dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
elif isinstance(self.dt, datetime.date):
self.dt_str = self.dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
elif isinstance(self.dt, datetime.time):
self.dt_str = self.dt.strftime(DEFAULT_SERVER_TIME_FORMAT)
# Pass a string
self.assertEqual(
self.expected,
self.rl.datetime_formatter(
self.dt_str,
**self.kwargs))
# Pass a unicode
self.assertEqual(
self.expected,
self.rl.datetime_formatter(
unicode(self.dt_str),
**self.kwargs))
super(FormatterCase, self).tearDown()
def test_datetime(self):
"""Format a datetime."""
self.format = "%s %s" % (self.d_fmt, self.t_fmt)
self.kwargs = {"template": MODE_DATETIME}
def test_date(self):
"""Format a date."""
self.format = self.d_fmt
self.kwargs = {"template": MODE_DATE}
self.dt = self.dt.date()
def test_time(self):
"""Format times, including float ones."""
self.format = self.t_fmt
self.kwargs = {"template": MODE_TIME}
self.dt = self.dt.time()
# Test float times
for n in range(50):
n = n + random()
# Patch values with >= 24 hours
fmt = self.format.replace("%H", "%02d" % n)
time = (datetime.datetime.min +
datetime.timedelta(hours=n)).time()
self.assertEqual(
time.strftime(fmt),
self.rl.datetime_formatter(n, **self.kwargs))
def test_custom_separator(self):
"""Format a datetime with a custom separator."""
sep = "T"
self.format = "%s%s%s" % (self.d_fmt, sep, self.t_fmt)
self.kwargs = {"template": MODE_DATETIME, "separator": sep}
Loading…
Cancel
Save