diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 8283626..0000000 --- a/.coveragerc +++ /dev/null @@ -1,8 +0,0 @@ -[run] -branch = True -source = oslo_i18n -omit = oslo_i18n/tests/* - -[report] -ignore_errors = True -precision = 2 diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 9d826ce..0000000 --- a/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -*~ -*.swp -*.pyc -*.log -.coverage -.venv -.tox -cover/ -oslo.i18n.egg-info/ -.openstack-common-venv/ -skeleton.egg-info/ -build/ -dist/ -doc/source/api -AUTHORS -.update-venv/ -ChangeLog -openstack/versioninfo -*.egg -openstack/common/db/*.sqlite -.testrepository/ -.project -.pydevproject -etc/openstack.conf.sample diff --git a/.gitreview b/.gitreview deleted file mode 100644 index 61b80ba..0000000 --- a/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=openstack/oslo.i18n.git diff --git a/.mailmap b/.mailmap deleted file mode 100644 index cc92f17..0000000 --- a/.mailmap +++ /dev/null @@ -1,3 +0,0 @@ -# Format is: -# -# \ No newline at end of file diff --git a/.testr.conf b/.testr.conf deleted file mode 100644 index fb62267..0000000 --- a/.testr.conf +++ /dev/null @@ -1,7 +0,0 @@ -[DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ - OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ - OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \ - ${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list \ No newline at end of file diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index fe2c9be..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,16 +0,0 @@ -If you would like to contribute to the development of OpenStack, -you must follow the steps in this page: - - http://docs.openstack.org/infra/manual/developers.html - -Once those steps have been completed, changes to OpenStack -should be submitted for review via the Gerrit tool, following -the workflow documented at: - - http://docs.openstack.org/infra/manual/developers.html#development-workflow - -Pull requests submitted through GitHub will be ignored. - -Bugs should be filed on Launchpad, not GitHub: - - https://bugs.launchpad.net/oslo.i18n \ No newline at end of file diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index 8f0f190..0000000 --- a/HACKING.rst +++ /dev/null @@ -1,4 +0,0 @@ - Style Commandments -=============================================== - -Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/ \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 67db858..0000000 --- a/LICENSE +++ /dev/null @@ -1,175 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. diff --git a/README.rst b/README.rst deleted file mode 100644 index 91fcef1..0000000 --- a/README.rst +++ /dev/null @@ -1,20 +0,0 @@ -================================================== - oslo.i18n -- Oslo Internationalization Utilities -================================================== - -.. image:: https://img.shields.io/pypi/v/oslo.i18n.svg - :target: https://pypi.python.org/pypi/oslo.i18n/ - :alt: Latest Version - -.. image:: https://img.shields.io/pypi/dm/oslo.i18n.svg - :target: https://pypi.python.org/pypi/oslo.i18n/ - :alt: Downloads - -The oslo.i18n library contain utilities for working with -internationalization (i18n) features, especially translation for text -strings in an application or library. - -* Free software: Apache license -* Documentation: http://docs.openstack.org/developer/oslo.i18n -* Source: http://git.openstack.org/cgit/openstack/oslo.i18n -* Bugs: http://bugs.launchpad.net/oslo.i18n diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..e6abc94 --- /dev/null +++ b/README.txt @@ -0,0 +1,13 @@ +This project is no longer maintained. + +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". + +Use instead the project deb-python-oslo.i18n at +http://git.openstack.org/cgit/openstack/deb-python-oslo.i18n . + +For any further questions, please email +openstack-dev@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/babel.cfg b/babel.cfg deleted file mode 100644 index efceab8..0000000 --- a/babel.cfg +++ /dev/null @@ -1 +0,0 @@ -[python: **.py] diff --git a/doc/source/api.rst b/doc/source/api.rst deleted file mode 100644 index 02095f7..0000000 --- a/doc/source/api.rst +++ /dev/null @@ -1,39 +0,0 @@ -===== - API -===== - -oslo_i18n -========= - -.. automodule:: oslo_i18n - -.. autoclass:: oslo_i18n.TranslatorFactory - :members: - -.. seealso:: - - An example of using a :class:`TranslatorFactory` is provided in - :ref:`integration-module`. - -.. autofunction:: oslo_i18n.enable_lazy - -.. seealso:: - - :ref:`lazy-translation` - -.. autofunction:: oslo_i18n.translate - -.. autofunction:: oslo_i18n.get_available_languages - -oslo_i18n.log -============= - -.. automodule:: oslo_i18n.log - :members: - -oslo_i18n.fixture -================= - -.. automodule:: oslo_i18n.fixture - :members: - :special-members: diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100755 index ef1b1b3..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: utf-8 -*- -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import os -import sys - -sys.path.insert(0, os.path.abspath('../..')) -# -- General configuration ---------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [ - 'sphinx.ext.autodoc', - #'sphinx.ext.intersphinx', - 'oslosphinx' -] - -# autodoc generation is a bit aggressive and a nuisance when doing heavy -# text edit cycles. -# execute "export SPHINX_DEBUG=1" in your terminal to disable - -# The suffix of source filenames. -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'oslo.i18n' -copyright = u'2014, OpenStack Foundation' - -# If true, '()' will be appended to :func: etc. cross-reference text. -add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = True - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -# html_theme_path = ["."] -# html_theme = '_theme' -# html_static_path = ['static'] - -html_use_modindex = True - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto/manual]). -latex_documents = [ - ('index', - '%s.tex' % project, - u'%s Documentation' % project, - u'OpenStack Foundation', 'manual'), -] - -# Example configuration for intersphinx: refer to the Python standard library. -#intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/doc/source/contributing.rst b/doc/source/contributing.rst deleted file mode 100644 index 2ca75d1..0000000 --- a/doc/source/contributing.rst +++ /dev/null @@ -1,5 +0,0 @@ -============== - Contributing -============== - -.. include:: ../../CONTRIBUTING.rst diff --git a/doc/source/guidelines.rst b/doc/source/guidelines.rst deleted file mode 100644 index e610f53..0000000 --- a/doc/source/guidelines.rst +++ /dev/null @@ -1,237 +0,0 @@ -================================= - Guidelines for Use In OpenStack -================================= - -The OpenStack I18N team has a limited capacity to translate messages, -so we want to make their work as effective as possible by identifying -the most useful text for them to translate. All text messages *the -user sees* via exceptions or API calls should be marked for -translation. However, some exceptions are used internally to signal -error conditions between modules and are not intended to be presented -to the user. Those do not need to be translated. - -.. seealso:: - - * :doc:`usage` - * :doc:`api` - -Gettext Contextual Form and Plural Form -======================================= - -Sometimes under different contexts, the same word should be -translated into different phrases using -:py:attr:`TranslatorFactory.contextual_form `. - -And recommend the following code to use contextual form:: - - # The contextual translation function using the name "_C" - _C = _translators.contextual_form - - ... - msg = _C('context', 'string') - -In some languages, sometimes the translated strings are different -with different item counts using -:py:attr:`TranslatorFactory.plural_form ` - -And recommend the following code to use plural form:: - - # The plural translation function using the name "_P" - _P = _translators.plural_form - - ... - msg = _P('single', 'plural', count) - -The contextual form and plural form are used only when needed. -By default, the translation should use the ``_()``. - -.. note:: - These two functions were only available in oslo.i18n >= 2.1.0. - -Log Translation -=============== - -OpenStack supports translating some log levels using separate message -catalogs, and so has separate marker functions. These well-known names -are used by the build system jobs that extract the messages from the -source code and pass it to the translation tool. - -========== ========== - Level Function -========== ========== - INFO ``_LI()`` - WARNING ``_LW()`` - ERROR ``_LE()`` - CRITICAL ``_LC()`` -========== ========== - -.. note:: - * Debug level log messages are not translated. - * LOG.exception creates an ERROR level log, so when a marker function is - used (see below) ``_LE()`` should be used. - - -Using a Marker Function -======================= -The marker functions are used to mark the translatable strings in the -code. The strings are extracted into catalogs using a tool that -looks for these specific markers, so the function argument must just -be a string. - -For example: **do not do this**:: - - # WRONG - msg = _(variable_containing_msg) - w_msg = _LW(variable_warning_msg) - -Instead, use this style:: - - # RIGHT - msg = _('My message.') - w_msg = _LW('My warning message') - - -Choosing a Marker Function -========================== - -The purpose of the different marker functions is to separate the -translatable messages into different catalogs, which the translation -teams can prioritize translating. It is important to choose the right -marker function, to ensure that strings the user sees will be -translated and to help the translation team manage their work load. - -Everything marked with ``_()`` will be translated. Prioritizing the -catalogs created from strings marked with the log marker functions is -up to the individual translation teams and their users, but it is -expected that they will work on critical and error messages before -warning or info. - -``_()`` is preferred for any user facing message, even if it is also -going to a log file. This ensures that the translated version of the -message will be available to the user. - -The log marker functions (``_LI()``, ``_LW()``, ``_LE()``, and ``_LC()``) -must only be used when the message is only sent directly to the log. -Anytime that the message will be passed outside of the current context -(for example as part of an exception) the ``_()`` marker function -must be used. - -A common pattern is to define a single message object and use it more -than once, for the log call and the exception. In that case, ``_()`` -must be used because the message is going to appear in an exception that -may be presented to the user. - -For example, **do not do this**:: - - # WRONG - msg = _LE('There was an error.') - LOG.exception(msg) - raise LocalExceptionClass(msg) - -Instead, use this style:: - - # RIGHT - msg = _('There was an error.') - LOG.exception(msg) - raise LocalExceptionClass(msg) - -Except in the case above, ``_()`` should not be used for translating -log messages. This avoids having the same string in two message -catalogs, possibly translated differently by two different -translators. The log message will translate properly because when -the message is not found in the log specific catalog the ``_()`` -catalog will be used. - -If a common message is not being used, they should each be treated -separately with respect to choosing a marker function. - -For example, **do not do this**:: - - # WRONG - LOG.exception(_('There was an error.')) - raise LocalExceptionClass(_('An error occured.')) - -Instead, use this style:: - - # RIGHT - LOG.exception(_LE('There was an error.')) - raise LocalExceptionClass(_('An error occured.')) - - -Adding Variables to Translated Messages -======================================= - -Translated messages should not be combined with other literal strings -to create partially translated messages. For example, **do not do -this**:: - - # WRONG - raise ValueError(_('some message') + ': variable=%s' % variable) - -Instead, use this style:: - - # RIGHT - raise ValueError(_('some message: variable=%s') % variable) - -Including the variable reference inside the translated message allows -the translator to take into account grammar rules, differences in -left-right vs. right-left rendering, and other factors to make the -translated message more useful to the end user. - -Any message with more than one variable should use named interpolation -instead of positional, to allow translators to move the variables -around in the string to account for differences in grammar and writing -direction. - -For example, **do not do this**:: - - # WRONG - raise ValueError(_('some message: v1=%s v2=%s') % (v1, v2)) - -Instead, use this style:: - - # RIGHT - raise ValueError(_('some message: v1=%(v1)s v2=%(v2)s') % {'v1': v1, 'v2': v2}) - - -Adding Variables to Log Messages -================================ - -String interpolation should be delayed to be handled by the logging -code, rather than being done at the point of the logging call. For -example, **do not do this**:: - - # WRONG - LOG.info(_LI('some message: variable=%s') % variable) - -Instead, use this style:: - - # RIGHT - LOG.info(_LI('some message: variable=%s'), variable) - -This allows the logging package to skip creating the formatted log -message if the message is not going to be emitted because of the -current log level. - -Avoid Forcing the Translation of Translatable Variables -======================================================= - -Translation can also be delayed for variables that potentially contain -translatable objects such as exceptions. - -Whenever possible translation should not be forced by use of :func:`str`, -:func:`unicode`, or :func:`six.text_type` on a message being used with -a format string. - -For example, **do not do this**:: - - # WRONG - LOG.info(_LI('some message: exception=%s'), six.text_type(exc)) - -Instead, use this style:: - - # RIGHT - LOG.info(_LI('some message: exception=%s'), exc) - -This allows the translation of the translatable replacement text to be -delayed until the message is translated. diff --git a/doc/source/history.rst b/doc/source/history.rst deleted file mode 100644 index 69ed4fe..0000000 --- a/doc/source/history.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../ChangeLog diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index fde034a..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,33 +0,0 @@ -================================================== - oslo.i18n -- Oslo Internationalization Utilities -================================================== - -The oslo.i18n library contain utilities for working with -internationalization (i18n) features, especially translation for text -strings in an application or library. - -Contents -======== - -.. toctree:: - :maxdepth: 2 - - usage - guidelines - api - policy - contributing - -Release Notes -============= - -.. toctree:: - :maxdepth: 1 - - history - -Indices and tables -================== - -* :ref:`modindex` -* :ref:`search` diff --git a/doc/source/policy.rst b/doc/source/policy.rst deleted file mode 100644 index 7ff67af..0000000 --- a/doc/source/policy.rst +++ /dev/null @@ -1,9 +0,0 @@ -================ - Policy History -================ - -* `Discussion from Havana Summit `__ -* `Discussion from Icehouse Summit `__ -* `Discussion from Juno Summit `__ -* `I18n team wiki page `__ -* `LoggingStandards wiki page `__ diff --git a/doc/source/usage.rst b/doc/source/usage.rst deleted file mode 100644 index 14c0b35..0000000 --- a/doc/source/usage.rst +++ /dev/null @@ -1,218 +0,0 @@ -===================================================== - How to Use oslo.i18n in Your Application or Library -===================================================== - -Installing -========== - -At the command line:: - - $ pip install oslo.i18n - -.. _integration-module: - -Creating an Integration Module -============================== - -To use oslo.i18n in a project (e.g. myapp), you will need to create a -small integration module to hold an instance of -:class:`~oslo_i18n.TranslatorFactory` and references to -the marker functions the factory creates. - -.. note:: - - Libraries probably do not want to expose the new integration module - as part of their public API, so rather than naming it - ``myapp.i18n`` it should be called ``myapp._i18n`` to indicate that - it is a private implementation detail, and not meant to be used - outside of the library's own code. - -.. code-block:: python - - # myapp/_i18n.py - - import oslo_i18n - - DOMAIN = "myapp" - - _translators = oslo_i18n.TranslatorFactory(domain=DOMAIN) - - # The primary translation function using the well-known name "_" - _ = _translators.primary - - # The contextual translation function using the name "_C" - # requires oslo.i18n >=2.1.0 - _C = _translators.contextual_form - - # The plural translation function using the name "_P" - # requires oslo.i18n >=2.1.0 - _P = _translators.plural_form - - # Translators for log levels. - # - # The abbreviated names are meant to reflect the usual use of a short - # name like '_'. The "L" is for "log" and the other letter comes from - # the level. - _LI = _translators.log_info - _LW = _translators.log_warning - _LE = _translators.log_error - _LC = _translators.log_critical - - - def get_available_languages(): - return oslo_i18n.get_available_languages(DOMAIN) - -Then, in the rest of your code, use the appropriate marker function -for each message: - -.. code-block:: python - - from myapp._i18n import _, _LW, _LE - - # ... - - variable = "openstack" - LOG.warning(_LW('warning message: %s'), variable) - - # ... - - try: - - # ... - - except AnException1: - - # Log only - LOG.exception(_LE('exception message')) - - except AnException2: - - # Raise only - raise RuntimeError(_('exception message')) - - else: - - # Log and Raise - msg = _('Unexpected error message') - LOG.exception(msg) - raise RuntimeError(msg) - -.. note:: - - The import of multiple modules from _i18n on a single line is - a valid exception to - `OpenStack Style Guidelines `_ - for import statements. - - -It is important to use the marker functions (e.g. _LI), rather than -the longer form of the name, because the tool that scans the source -code for translatable strings looks for the marker function names. - -.. warning:: - - The old method of installing a version of ``_()`` in the builtins - namespace is deprecated. Modifying the global namespace affects - libraries as well as the application, so it may interfere with - proper message catalog lookups. Calls to - :func:`gettextutils.install` should be replaced with the - application or library integration module described here. - -Handling hacking Objections to Imports -====================================== - -The `OpenStack Style Guidelines `_ -prefer importing modules and accessing names from those modules after -import, rather than importing the names directly. For example: - -:: - - # WRONG - from foo import bar - - bar() - - # RIGHT - - import foo - - foo.bar() - -The linting tool hacking_ will typically complain about importing -names from within modules. It is acceptable to bypass this for the -translation marker functions, because they must have specific names -and their use pattern is dictated by the message catalog extraction -tools rather than our style guidelines. To bypass the hacking check -for imports from this integration module, add an import exception to -``tox.ini``. - -For example:: - - # tox.ini - [hacking] - import_exceptions = myapp._i18n - -.. _hacking: https://pypi.python.org/pypi/hacking - -.. _lazy-translation: - -Lazy Translation -================ - -Lazy translation delays converting a message string to the translated -form as long as possible, including possibly never if the message is -not logged or delivered to the user in some other way. It also -supports logging translated messages in multiple languages, by -configuring separate log handlers. - -Lazy translation is implemented by returning a special object from the -translation function, instead of a unicode string. That special -message object supports some, but not all, string manipulation -APIs. For example, concatenation with addition is not supported, but -interpolation of variables is supported. Depending on how translated -strings are used in an application, these restrictions may mean that -lazy translation cannot be used, and so it is not enabled by default. - -To enable lazy translation, call :func:`enable_lazy`. - -:: - - import oslo_i18n - - oslo_i18n.enable_lazy() - -Translating Messages -==================== - -Use :func:`~oslo_i18n.translate` to translate strings to -a specific locale. :func:`translate` handles delayed translation and -strings that have already been translated immediately. It should be -used at the point where the locale to be used is known, which is often -just prior to the message being returned or a log message being -emitted. - -:: - - import oslo_i18n - - trans_msg = oslo_i18n.translate(msg, my_locale) - -If a locale is not specified the default locale is used. - -Available Languages -=================== - -Only the languages that have translations provided are available for -translation. To determine which languages are available the -:func:`~oslo_i18n.get_available_languages` is provided. The integration -module provides a domain defined specific function. - -.. code-block:: python - - import myapp._i18n - - languages = myapp._i18n.get_available_languages() - -.. seealso:: - - * :doc:`guidelines` diff --git a/oslo_i18n/__init__.py b/oslo_i18n/__init__.py deleted file mode 100644 index 4602749..0000000 --- a/oslo_i18n/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ._factory import * -from ._gettextutils import * -from ._lazy import * -from ._translate import * diff --git a/oslo_i18n/_factory.py b/oslo_i18n/_factory.py deleted file mode 100644 index c732b01..0000000 --- a/oslo_i18n/_factory.py +++ /dev/null @@ -1,205 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -"""Translation function factory -""" - -import gettext -import os - -import six - -from oslo_i18n import _lazy -from oslo_i18n import _locale -from oslo_i18n import _message - - -__all__ = [ - 'TranslatorFactory', -] - -# magic gettext number to separate context from message -CONTEXT_SEPARATOR = _message.CONTEXT_SEPARATOR - - -class TranslatorFactory(object): - "Create translator functions" - - def __init__(self, domain, localedir=None): - """Establish a set of translation functions for the domain. - - :param domain: Name of translation domain, - specifying a message catalog. - :type domain: str - :param localedir: Directory with translation catalogs. - :type localedir: str - """ - self.domain = domain - if localedir is None: - variable_name = _locale.get_locale_dir_variable_name(domain) - localedir = os.environ.get(variable_name) - self.localedir = localedir - - def _make_translation_func(self, domain=None): - """Return a translation function ready for use with messages. - - The returned function takes a single value, the unicode string - to be translated. The return type varies depending on whether - lazy translation is being done. When lazy translation is - enabled, :class:`Message` objects are returned instead of - regular :class:`unicode` strings. - - The domain argument can be specified to override the default - from the factory, but the localedir from the factory is always - used because we assume the log-level translation catalogs are - installed in the same directory as the main application - catalog. - - """ - if domain is None: - domain = self.domain - t = gettext.translation(domain, - localedir=self.localedir, - fallback=True) - # Use the appropriate method of the translation object based - # on the python version. - m = t.gettext if six.PY3 else t.ugettext - - def f(msg): - """oslo_i18n.gettextutils translation function.""" - if _lazy.USE_LAZY: - return _message.Message(msg, domain=domain) - return m(msg) - return f - - def _make_contextual_translation_func(self, domain=None): - """Return a translation function ready for use with context messages. - - The returned function takes two values, the context of - the unicode string, the unicode string to be translated. - The returned type is the same as - :method:`TranslatorFactory._make_translation_func`. - - The domain argument is the same as - :method:`TranslatorFactory._make_translation_func`. - - """ - if domain is None: - domain = self.domain - t = gettext.translation(domain, - localedir=self.localedir, - fallback=True) - # Use the appropriate method of the translation object based - # on the python version. - m = t.gettext if six.PY3 else t.ugettext - - def f(ctx, msg): - """oslo.i18n.gettextutils translation with context function.""" - if _lazy.USE_LAZY: - msgid = (ctx, msg) - return _message.Message(msgid, domain=domain, - has_contextual_form=True) - - msgctx = "%s%s%s" % (ctx, CONTEXT_SEPARATOR, msg) - s = m(msgctx) - if CONTEXT_SEPARATOR in s: - # Translation not found - return msg - return s - return f - - def _make_plural_translation_func(self, domain=None): - """Return a plural translation function ready for use with messages. - - The returned function takes three values, the single form of - the unicode string, the plural form of the unicode string, - the count of items to be translated. - The returned type is the same as - :method:`TranslatorFactory._make_translation_func`. - - The domain argument is the same as - :method:`TranslatorFactory._make_translation_func`. - - """ - if domain is None: - domain = self.domain - t = gettext.translation(domain, - localedir=self.localedir, - fallback=True) - # Use the appropriate method of the translation object based - # on the python version. - m = t.ngettext if six.PY3 else t.ungettext - - def f(msgsingle, msgplural, msgcount): - """oslo.i18n.gettextutils plural translation function.""" - if _lazy.USE_LAZY: - msgid = (msgsingle, msgplural, msgcount) - return _message.Message(msgid, domain=domain, - has_plural_form=True) - return m(msgsingle, msgplural, msgcount) - return f - - @property - def primary(self): - "The default translation function." - return self._make_translation_func() - - @property - def contextual_form(self): - """The contextual translation function. - - The returned function takes two values, the context of - the unicode string, the unicode string to be translated. - - .. versionadded:: 2.1.0 - - """ - return self._make_contextual_translation_func() - - @property - def plural_form(self): - """The plural translation function. - - The returned function takes three values, the single form of - the unicode string, the plural form of the unicode string, - the count of items to be translated. - - .. versionadded:: 2.1.0 - - """ - return self._make_plural_translation_func() - - def _make_log_translation_func(self, level): - return self._make_translation_func(self.domain + '-log-' + level) - - @property - def log_info(self): - "Translate info-level log messages." - return self._make_log_translation_func('info') - - @property - def log_warning(self): - "Translate warning-level log messages." - return self._make_log_translation_func('warning') - - @property - def log_error(self): - "Translate error-level log messages." - return self._make_log_translation_func('error') - - @property - def log_critical(self): - "Translate critical-level log messages." - return self._make_log_translation_func('critical') diff --git a/oslo_i18n/_gettextutils.py b/oslo_i18n/_gettextutils.py deleted file mode 100644 index 75a8313..0000000 --- a/oslo_i18n/_gettextutils.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""gettextutils provides a wrapper around gettext for OpenStack projects -""" - -import copy -import gettext -import os - -from babel import localedata -import six - -from oslo_i18n import _factory -from oslo_i18n import _locale - -__all__ = [ - 'install', - 'get_available_languages', -] - - -def install(domain): - """Install a _() function using the given translation domain. - - Given a translation domain, install a _() function using gettext's - install() function. - - The main difference from gettext.install() is that we allow - overriding the default localedir (e.g. /usr/share/locale) using - a translation-domain-specific environment variable (e.g. - NOVA_LOCALEDIR). - - :param domain: the translation domain - """ - from six import moves - tf = _factory.TranslatorFactory(domain) - moves.builtins.__dict__['_'] = tf.primary - - -_AVAILABLE_LANGUAGES = {} - - -def get_available_languages(domain): - """Lists the available languages for the given translation domain. - - :param domain: the domain to get languages for - """ - if domain in _AVAILABLE_LANGUAGES: - return copy.copy(_AVAILABLE_LANGUAGES[domain]) - - localedir = os.environ.get(_locale.get_locale_dir_variable_name(domain)) - find = lambda x: gettext.find(domain, - localedir=localedir, - languages=[x]) - - # NOTE(mrodden): en_US should always be available (and first in case - # order matters) since our in-line message strings are en_US - language_list = ['en_US'] - locale_identifiers = localedata.locale_identifiers() - language_list.extend(language for language in locale_identifiers - if find(language)) - - # In Babel 1.3, locale_identifiers() doesn't list some OpenStack supported - # locales (e.g. 'zh_CN', and 'zh_TW') so we add the locales explicitly if - # necessary so that they are listed as supported. - aliases = {'zh': 'zh_CN', - 'zh_Hant_HK': 'zh_HK', - 'zh_Hant': 'zh_TW', - 'fil': 'tl_PH'} - - language_list.extend(alias for locale, alias in six.iteritems(aliases) - if (locale in language_list and - alias not in language_list)) - - _AVAILABLE_LANGUAGES[domain] = language_list - return copy.copy(language_list) diff --git a/oslo_i18n/_i18n.py b/oslo_i18n/_i18n.py deleted file mode 100644 index 7755571..0000000 --- a/oslo_i18n/_i18n.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -"""Translation support for messages in this library. -""" - -from oslo_i18n import _factory - -# Create the global translation functions. -_translators = _factory.TranslatorFactory('oslo_i18n') - -# The primary translation function using the well-known name "_" -_ = _translators.primary diff --git a/oslo_i18n/_lazy.py b/oslo_i18n/_lazy.py deleted file mode 100644 index 82de17d..0000000 --- a/oslo_i18n/_lazy.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -__all__ = [ - 'enable_lazy', -] - -USE_LAZY = False - - -def enable_lazy(enable=True): - """Convenience function for configuring _() to use lazy gettext - - Call this at the start of execution to enable the gettextutils._ - function to use lazy gettext functionality. This is useful if - your project is importing _ directly instead of using the - gettextutils.install() way of importing the _ function. - - :param enable: Flag indicating whether lazy translation should be - turned on or off. Defaults to True. - :type enable: bool - - """ - global USE_LAZY - USE_LAZY = enable diff --git a/oslo_i18n/_locale.py b/oslo_i18n/_locale.py deleted file mode 100644 index 51908db..0000000 --- a/oslo_i18n/_locale.py +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -def get_locale_dir_variable_name(domain): - """Build environment variable name for local dir. - - Convert a translation domain name to a variable for specifying - a separate locale dir. - - """ - return domain.upper().replace('.', '_').replace('-', '_') + '_LOCALEDIR' diff --git a/oslo_i18n/_message.py b/oslo_i18n/_message.py deleted file mode 100644 index 0bd83c5..0000000 --- a/oslo_i18n/_message.py +++ /dev/null @@ -1,233 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -"""Private Message class for lazy translation support. -""" - -import copy -import gettext -import locale -import logging -import os -import warnings - -import six - -from oslo_i18n import _locale -from oslo_i18n import _translate - -# magic gettext number to separate context from message -CONTEXT_SEPARATOR = "\x04" - - -LOG = logging.getLogger(__name__) - - -class Message(six.text_type): - """A Message object is a unicode object that can be translated. - - Translation of Message is done explicitly using the translate() method. - For all non-translation intents and purposes, a Message is simply unicode, - and can be treated as such. - """ - - def __new__(cls, msgid, msgtext=None, params=None, - domain='oslo', has_contextual_form=False, - has_plural_form=False, *args): - """Create a new Message object. - - In order for translation to work gettext requires a message ID, this - msgid will be used as the base unicode text. It is also possible - for the msgid and the base unicode text to be different by passing - the msgtext parameter. - """ - # If the base msgtext is not given, we use the default translation - # of the msgid (which is in English) just in case the system locale is - # not English, so that the base text will be in that locale by default. - if not msgtext: - msgtext = Message._translate_msgid(msgid, domain) - # We want to initialize the parent unicode with the actual object that - # would have been plain unicode if 'Message' was not enabled. - msg = super(Message, cls).__new__(cls, msgtext) - msg.msgid = msgid - msg.domain = domain - msg.params = params - msg.has_contextual_form = has_contextual_form - msg.has_plural_form = has_plural_form - return msg - - def translate(self, desired_locale=None): - """Translate this message to the desired locale. - - :param desired_locale: The desired locale to translate the message to, - if no locale is provided the message will be - translated to the system's default locale. - - :returns: the translated message in unicode - """ - - translated_message = Message._translate_msgid(self.msgid, - self.domain, - desired_locale, - self.has_contextual_form, - self.has_plural_form) - - if self.params is None: - # No need for more translation - return translated_message - - # This Message object may have been formatted with one or more - # Message objects as substitution arguments, given either as a single - # argument, part of a tuple, or as one or more values in a dictionary. - # When translating this Message we need to translate those Messages too - translated_params = _translate.translate_args(self.params, - desired_locale) - - return self._safe_translate(translated_message, translated_params) - - @staticmethod - def _translate_msgid(msgid, domain, desired_locale=None, - has_contextual_form=False, has_plural_form=False): - if not desired_locale: - system_locale = locale.getdefaultlocale() - # If the system locale is not available to the runtime use English - if not system_locale or not system_locale[0]: - desired_locale = 'en_US' - else: - desired_locale = system_locale[0] - - locale_dir = os.environ.get( - _locale.get_locale_dir_variable_name(domain) - ) - lang = gettext.translation(domain, - localedir=locale_dir, - languages=[desired_locale], - fallback=True) - - if not has_contextual_form and not has_plural_form: - # This is the most common case, so check it first. - translator = lang.gettext if six.PY3 else lang.ugettext - translated_message = translator(msgid) - - elif has_contextual_form and has_plural_form: - # Reserved for contextual and plural translation function, - # which is not yet implemented. - raise ValueError("Unimplemented.") - - elif has_contextual_form: - (msgctx, msgtxt) = msgid - translator = lang.gettext if six.PY3 else lang.ugettext - - msg_with_ctx = "%s%s%s" % (msgctx, CONTEXT_SEPARATOR, msgtxt) - translated_message = translator(msg_with_ctx) - - if CONTEXT_SEPARATOR in translated_message: - # Translation not found, use the original text - translated_message = msgtxt - - elif has_plural_form: - (msgsingle, msgplural, msgcount) = msgid - translator = lang.ngettext if six.PY3 else lang.ungettext - translated_message = translator(msgsingle, msgplural, msgcount) - - return translated_message - - def _safe_translate(self, translated_message, translated_params): - """Trap translation errors and fall back to default translation. - - :param translated_message: the requested translation - - :param translated_params: the params to be inserted - - :return: if parameter insertion is successful then it is the - translated_message with the translated_params inserted, if the - requested translation fails then it is the default translation - with the params - """ - - try: - translated_message = translated_message % translated_params - except (KeyError, TypeError) as err: - # KeyError for parameters named in the translated_message - # but not found in translated_params and TypeError for - # type strings that do not match the type of the - # parameter. - # - # Log the error translating the message and use the - # original message string so the translator's bad message - # catalog doesn't break the caller. - # Do not translate this log message even if it is used as a - # warning message as a wrong translation of this message could - # cause infinite recursion - msg = (u'Failed to insert replacement values into translated ' - u'message %s (Original: %r): %s') - warnings.warn(msg % (translated_message, self.msgid, err)) - LOG.debug(msg, translated_message, self.msgid, err) - - translated_message = self.msgid % translated_params - - return translated_message - - def __mod__(self, other): - # When we mod a Message we want the actual operation to be performed - # by the base class (i.e. unicode()), the only thing we do here is - # save the original msgid and the parameters in case of a translation - params = self._sanitize_mod_params(other) - unicode_mod = self._safe_translate(six.text_type(self), params) - modded = Message(self.msgid, - msgtext=unicode_mod, - params=params, - domain=self.domain) - return modded - - def _sanitize_mod_params(self, other): - """Sanitize the object being modded with this Message. - - - Add support for modding 'None' so translation supports it - - Trim the modded object, which can be a large dictionary, to only - those keys that would actually be used in a translation - - Snapshot the object being modded, in case the message is - translated, it will be used as it was when the Message was created - """ - if other is None: - params = (other,) - elif isinstance(other, dict): - # Merge the dictionaries - # Copy each item in case one does not support deep copy. - params = {} - if isinstance(self.params, dict): - params.update((key, self._copy_param(val)) - for key, val in self.params.items()) - params.update((key, self._copy_param(val)) - for key, val in other.items()) - else: - params = self._copy_param(other) - return params - - def _copy_param(self, param): - try: - return copy.deepcopy(param) - except Exception: - # Fallback to casting to unicode this will handle the - # python code-like objects that can't be deep-copied - return six.text_type(param) - - def __add__(self, other): - from oslo_i18n._i18n import _ - msg = _('Message objects do not support addition.') - raise TypeError(msg) - - def __radd__(self, other): - return self.__add__(other) diff --git a/oslo_i18n/_translate.py b/oslo_i18n/_translate.py deleted file mode 100644 index 1809e1e..0000000 --- a/oslo_i18n/_translate.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import six - -__all__ = [ - 'translate', -] - - -def translate(obj, desired_locale=None): - """Gets the translated unicode representation of the given object. - - If the object is not translatable it is returned as-is. - - If the desired_locale argument is None the object is translated to - the system locale. - - :param obj: the object to translate - :param desired_locale: the locale to translate the message to, if None the - default system locale will be used - :returns: the translated object in unicode, or the original object if - it could not be translated - - """ - from oslo_i18n import _message # avoid circular dependency at module level - message = obj - if not isinstance(message, _message.Message): - # If the object to translate is not already translatable, - # let's first get its unicode representation - message = six.text_type(obj) - if isinstance(message, _message.Message): - # Even after unicoding() we still need to check if we are - # running with translatable unicode before translating - return message.translate(desired_locale) - return obj - - -def translate_args(args, desired_locale=None): - """Translates all the translatable elements of the given arguments object. - - This method is used for translating the translatable values in method - arguments which include values of tuples or dictionaries. - If the object is not a tuple or a dictionary the object itself is - translated if it is translatable. - - If the locale is None the object is translated to the system locale. - - :param args: the args to translate - :param desired_locale: the locale to translate the args to, if None the - default system locale will be used - :returns: a new args object with the translated contents of the original - """ - if isinstance(args, tuple): - return tuple(translate(v, desired_locale) for v in args) - if isinstance(args, dict): - translated_dict = dict((key, translate(value, desired_locale)) - for key, value in six.iteritems(args)) - return translated_dict - return translate(args, desired_locale) diff --git a/oslo_i18n/fixture.py b/oslo_i18n/fixture.py deleted file mode 100644 index 35dc694..0000000 --- a/oslo_i18n/fixture.py +++ /dev/null @@ -1,165 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -"""Test fixtures for working with oslo_i18n. - -""" - -import gettext - -import fixtures -import six - -from oslo_i18n import _lazy -from oslo_i18n import _message - - -class Translation(fixtures.Fixture): - """Fixture for managing translatable strings. - - This class provides methods for creating translatable strings - using both lazy translation and immediate translation. It can be - used to generate the different types of messages returned from - oslo_i18n to test code that may need to know about the type to - handle them differently (for example, error handling in WSGI apps, - or logging). - - Use this class to generate messages instead of toggling the global - lazy flag and using the regular translation factory. - - """ - - def __init__(self, domain='test-domain'): - """Initialize the fixture. - - :param domain: The translation domain. This is not expected to - coincide with an actual set of message - catalogs, but it can. - :type domain: str - """ - self.domain = domain - - def lazy(self, msg): - """Return a lazily translated message. - - :param msg: Input message string. May optionally include - positional or named string interpolation markers. - :type msg: str or unicode - - """ - return _message.Message(msg, domain=self.domain) - - def immediate(self, msg): - """Return a string as though it had been translated immediately. - - :param msg: Input message string. May optionally include - positional or named string interpolation markers. - :type msg: str or unicode - - """ - return six.text_type(msg) - - -class ToggleLazy(fixtures.Fixture): - """Fixture to toggle lazy translation on or off for a test.""" - - def __init__(self, enabled): - """Force lazy translation on or off. - - :param enabled: Flag controlling whether to enable or disable - lazy translation, passed to :func:`~oslo_i18n.enable_lazy`. - :type enabled: bool - """ - super(ToggleLazy, self).__init__() - self._enabled = enabled - self._original_value = _lazy.USE_LAZY - - def setUp(self): - super(ToggleLazy, self).setUp() - self.addCleanup(self._restore_original) - _lazy.enable_lazy(self._enabled) - - def _restore_original(self): - _lazy.enable_lazy(self._original_value) - - -class _PrefixTranslator(gettext.NullTranslations): - """Translator that adds prefix to message ids - - NOTE: gettext.NullTranslations is an old style class - - :parm prefix: prefix to add to message id. If not specified (None) - then 'noprefix' is used. - :type prefix: string - - """ - - def __init__(self, fp=None, prefix='noprefix'): - gettext.NullTranslations.__init__(self, fp) - self.prefix = prefix - - def gettext(self, message): - msg = gettext.NullTranslations.gettext(self, message) - return self.prefix + msg - - def ugettext(self, message): - msg = gettext.NullTranslations.ugettext(self, message) - return self.prefix + msg - - -def _prefix_translations(*x, **y): - """Use message id prefixed with domain and language as translation - - """ - return _PrefixTranslator(prefix=x[0] + '/' + y['languages'][0] + ': ') - - -class PrefixLazyTranslation(fixtures.Fixture): - """Fixture to prefix lazy translation enabled messages - - Use of this fixture will cause messages supporting lazy translation to - be replaced with the message id prefixed with 'domain/language:'. - For example, 'oslo/en_US: message about something'. It will also - override the available languages returned from - oslo_18n.get_available_languages to the specified languages. - - This will enable tests to ensure that messages were translated lazily - with the specified language and not immediately with the default language. - - NOTE that this does not work unless lazy translation is enabled, so it - uses the ToggleLazy fixture to enable lazy translation. - - :param languages: list of languages to support. If not specified (None) - then ['en_US'] is used. - :type languages: list of strings - - """ - - _DEFAULT_LANG = 'en_US' - - def __init__(self, languages=None, locale=None): - super(PrefixLazyTranslation, self).__init__() - self.languages = languages or [PrefixLazyTranslation._DEFAULT_LANG] - self.locale = locale - - def setUp(self): - super(PrefixLazyTranslation, self).setUp() - self.useFixture(ToggleLazy(True)) - self.useFixture(fixtures.MonkeyPatch( - 'oslo_i18n._gettextutils.get_available_languages', - lambda *x, **y: self.languages)) - self.useFixture(fixtures.MonkeyPatch( - 'oslo_i18n.get_available_languages', - lambda *x, **y: self.languages)) - self.useFixture(fixtures.MonkeyPatch('gettext.translation', - _prefix_translations)) - self.useFixture(fixtures.MonkeyPatch('locale.getdefaultlocale', - lambda *x, **y: self.locale)) diff --git a/oslo_i18n/locale/de/LC_MESSAGES/oslo_i18n.po b/oslo_i18n/locale/de/LC_MESSAGES/oslo_i18n.po deleted file mode 100644 index 0a0b25a..0000000 --- a/oslo_i18n/locale/de/LC_MESSAGES/oslo_i18n.po +++ /dev/null @@ -1,26 +0,0 @@ -# Translations template for oslo.i18n. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.i18n project. -# -# Translators: -# Andreas Jaeger , 2014 -# Robert Simai, 2015 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.i18n 3.6.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-04 05:29+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-06-01 09:23+0000\n" -"Last-Translator: Andreas Jaeger \n" -"Language: de\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: German\n" - -msgid "Message objects do not support addition." -msgstr "Message-Objekte unterstützen keine Addition." diff --git a/oslo_i18n/locale/en_GB/LC_MESSAGES/oslo_i18n.po b/oslo_i18n/locale/en_GB/LC_MESSAGES/oslo_i18n.po deleted file mode 100644 index 26e2c59..0000000 --- a/oslo_i18n/locale/en_GB/LC_MESSAGES/oslo_i18n.po +++ /dev/null @@ -1,25 +0,0 @@ -# Translations template for oslo.i18n. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.i18n project. -# -# Translators: -# Andi Chandler , 2014 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.i18n 3.6.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-04 05:29+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2014-09-02 09:09+0000\n" -"Last-Translator: Andi Chandler \n" -"Language: en-GB\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: English (United Kingdom)\n" - -msgid "Message objects do not support addition." -msgstr "Message objects do not support addition." diff --git a/oslo_i18n/locale/es/LC_MESSAGES/oslo_i18n.po b/oslo_i18n/locale/es/LC_MESSAGES/oslo_i18n.po deleted file mode 100644 index 71d799a..0000000 --- a/oslo_i18n/locale/es/LC_MESSAGES/oslo_i18n.po +++ /dev/null @@ -1,25 +0,0 @@ -# Translations template for oslo.i18n. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.i18n project. -# -# Translators: -# Adriana Chisco Landazábal , 2015 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.i18n 3.6.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-04 05:29+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2015-06-22 09:03+0000\n" -"Last-Translator: Adriana Chisco Landazábal \n" -"Language: es\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: Spanish\n" - -msgid "Message objects do not support addition." -msgstr "Objectos de mensaje no soportan adición." diff --git a/oslo_i18n/locale/fr/LC_MESSAGES/oslo_i18n.po b/oslo_i18n/locale/fr/LC_MESSAGES/oslo_i18n.po deleted file mode 100644 index 3e97285..0000000 --- a/oslo_i18n/locale/fr/LC_MESSAGES/oslo_i18n.po +++ /dev/null @@ -1,26 +0,0 @@ -# Translations template for oslo.i18n. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.i18n project. -# -# Translators: -# Jonathan Dupart , 2014 -# Maxime COQUEREL , 2014 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.i18n 3.6.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-04 05:29+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2014-09-25 09:36+0000\n" -"Last-Translator: Jonathan Dupart \n" -"Language: fr\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: French\n" - -msgid "Message objects do not support addition." -msgstr "Les objects message ne supportent pas l'ajout." diff --git a/oslo_i18n/locale/it/LC_MESSAGES/oslo_i18n.po b/oslo_i18n/locale/it/LC_MESSAGES/oslo_i18n.po deleted file mode 100644 index 1b3dbf5..0000000 --- a/oslo_i18n/locale/it/LC_MESSAGES/oslo_i18n.po +++ /dev/null @@ -1,25 +0,0 @@ -# Translations template for oslo.i18n. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.i18n project. -# -# Translators: -# PierAlberto , 2014 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.i18n 3.6.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-04 05:29+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2014-08-24 11:27+0000\n" -"Last-Translator: PierAlberto \n" -"Language: it\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: Italian\n" - -msgid "Message objects do not support addition." -msgstr "I messaggi oggetti non supportano aggiunte." diff --git a/oslo_i18n/locale/ja/LC_MESSAGES/oslo_i18n.po b/oslo_i18n/locale/ja/LC_MESSAGES/oslo_i18n.po deleted file mode 100644 index 01b71ac..0000000 --- a/oslo_i18n/locale/ja/LC_MESSAGES/oslo_i18n.po +++ /dev/null @@ -1,18 +0,0 @@ -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.i18n 3.6.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-04 05:29+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2016-02-20 06:44+0000\n" -"Last-Translator: KATO Tomoyuki \n" -"Language-Team: Japanese\n" -"Language: ja\n" -"X-Generator: Zanata 3.7.3\n" -"Plural-Forms: nplurals=1; plural=0\n" - -msgid "Message objects do not support addition." -msgstr "メッセージオブジェクトは追加機能をサポートしていません。" diff --git a/oslo_i18n/locale/ko_KR/LC_MESSAGES/oslo_i18n.po b/oslo_i18n/locale/ko_KR/LC_MESSAGES/oslo_i18n.po deleted file mode 100644 index e8f31e2..0000000 --- a/oslo_i18n/locale/ko_KR/LC_MESSAGES/oslo_i18n.po +++ /dev/null @@ -1,25 +0,0 @@ -# Translations template for oslo.i18n. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.i18n project. -# -# Translators: -# Sungjin Kang , 2014 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.i18n 3.6.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-04 05:29+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2014-09-24 04:32+0000\n" -"Last-Translator: Sungjin Kang \n" -"Language: ko-KR\n" -"Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: Korean (South Korea)\n" - -msgid "Message objects do not support addition." -msgstr "메시지 객체는 추가 지원을하지 않습니다." diff --git a/oslo_i18n/locale/pl_PL/LC_MESSAGES/oslo_i18n.po b/oslo_i18n/locale/pl_PL/LC_MESSAGES/oslo_i18n.po deleted file mode 100644 index e375326..0000000 --- a/oslo_i18n/locale/pl_PL/LC_MESSAGES/oslo_i18n.po +++ /dev/null @@ -1,26 +0,0 @@ -# Translations template for oslo.i18n. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.i18n project. -# -# Translators: -# Łukasz Jernaś , 2014 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.i18n 3.6.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-04 05:29+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2014-08-21 11:28+0000\n" -"Last-Translator: Łukasz Jernaś \n" -"Language: pl-PL\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " -"|| n%100>=20) ? 1 : 2);\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: Polish (Poland)\n" - -msgid "Message objects do not support addition." -msgstr "Obiekty Message nie wspierają dodawania." diff --git a/oslo_i18n/locale/pt/LC_MESSAGES/oslo_i18n.po b/oslo_i18n/locale/pt/LC_MESSAGES/oslo_i18n.po deleted file mode 100644 index 89ea556..0000000 --- a/oslo_i18n/locale/pt/LC_MESSAGES/oslo_i18n.po +++ /dev/null @@ -1,25 +0,0 @@ -# Translations template for oslo.i18n. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.i18n project. -# -# Translators: -# MMSRS , 2015 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.i18n 3.6.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-04 05:29+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2015-08-11 05:02+0000\n" -"Last-Translator: MMSRS \n" -"Language: pt\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: Portuguese\n" - -msgid "Message objects do not support addition." -msgstr "Os objetos de mensagem não suportam a adição." diff --git a/oslo_i18n/locale/zh_CN/LC_MESSAGES/oslo_i18n.po b/oslo_i18n/locale/zh_CN/LC_MESSAGES/oslo_i18n.po deleted file mode 100644 index 1dbca44..0000000 --- a/oslo_i18n/locale/zh_CN/LC_MESSAGES/oslo_i18n.po +++ /dev/null @@ -1,25 +0,0 @@ -# Translations template for oslo.i18n. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the oslo.i18n project. -# -# Translators: -# Xiao Xi LIU , 2014 -# Andreas Jaeger , 2016. #zanata -msgid "" -msgstr "" -"Project-Id-Version: oslo.i18n 3.6.1.dev1\n" -"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n" -"POT-Creation-Date: 2016-06-04 05:29+0000\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2014-11-20 12:40+0000\n" -"Last-Translator: Xiao Xi LIU \n" -"Language: zh-CN\n" -"Plural-Forms: nplurals=1; plural=0;\n" -"Generated-By: Babel 2.0\n" -"X-Generator: Zanata 3.7.3\n" -"Language-Team: Chinese (China)\n" - -msgid "Message objects do not support addition." -msgstr "消息对象不支持添加操作。" diff --git a/oslo_i18n/log.py b/oslo_i18n/log.py deleted file mode 100644 index 563c1b3..0000000 --- a/oslo_i18n/log.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""logging utilities for translation -""" - -from logging import handlers - -from oslo_i18n import _translate - - -class TranslationHandler(handlers.MemoryHandler): - """Handler that translates records before logging them. - - When lazy translation is enabled in the application (see - :func:`~oslo_i18n.enable_lazy`), the :class:`TranslationHandler` - uses its locale configuration setting to determine how to - translate LogRecord objects before forwarding them to the - logging.Handler. - - When lazy translation is disabled, the message in the LogRecord is - converted to unicode without any changes and then forwarded to the - logging.Handler. - - The handler can be configured declaratively in the - ``logging.conf`` as follows:: - - [handlers] - keys = translatedlog, translator - - [handler_translatedlog] - class = handlers.WatchedFileHandler - args = ('/var/log/api-localized.log',) - formatter = context - - [handler_translator] - class = oslo_i18n.log.TranslationHandler - target = translatedlog - args = ('zh_CN',) - - If the specified locale is not available in the system, the handler will - log in the default locale. - - """ - - def __init__(self, locale=None, target=None): - """Initialize a TranslationHandler - - :param locale: locale to use for translating messages - :param target: logging.Handler object to forward - LogRecord objects to after translation - """ - # NOTE(luisg): In order to allow this handler to be a wrapper for - # other handlers, such as a FileHandler, and still be able to - # configure it using logging.conf, this handler has to extend - # MemoryHandler because only the MemoryHandlers' logging.conf - # parsing is implemented such that it accepts a target handler. - handlers.MemoryHandler.__init__(self, capacity=0, target=target) - self.locale = locale - - def setFormatter(self, fmt): - self.target.setFormatter(fmt) - - def emit(self, record): - # We save the message from the original record to restore it - # after translation, so other handlers are not affected by this - original_msg = record.msg - original_args = record.args - - try: - self._translate_and_log_record(record) - finally: - record.msg = original_msg - record.args = original_args - - def _translate_and_log_record(self, record): - record.msg = _translate.translate(record.msg, self.locale) - - # In addition to translating the message, we also need to translate - # arguments that were passed to the log method that were not part - # of the main message e.g., log.info(_('Some message %s'), this_one)) - record.args = _translate.translate_args(record.args, self.locale) - - self.target.emit(record) diff --git a/oslo_i18n/tests/__init__.py b/oslo_i18n/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/oslo_i18n/tests/fakes.py b/oslo_i18n/tests/fakes.py deleted file mode 100644 index 6bed973..0000000 --- a/oslo_i18n/tests/fakes.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2012 Intel Inc, OpenStack Foundation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Fakes For translation tests. -""" - -import gettext - - -class FakeTranslations(gettext.GNUTranslations): - """A test GNUTranslations class that takes a map of msg -> translations.""" - - def __init__(self, translations): - self.translations = translations - - # used by Python 3 - def gettext(self, msgid): - return self.translations.get(msgid, msgid) - - # used by Python 2 - def ugettext(self, msgid): - return self.translations.get(msgid, msgid) - - @staticmethod - def translator(locales_map): - """Build mock translator for the given locales. - - Returns a mock gettext.translation function that uses - individual TestTranslations to translate in the given locales. - - :param locales_map: A map from locale name to a translations map. - { - 'es': {'Hi': 'Hola', 'Bye': 'Adios'}, - 'zh': {'Hi': 'Ni Hao', 'Bye': 'Zaijian'} - } - - - """ - def _translation(domain, localedir=None, - languages=None, fallback=None): - if languages: - language = languages[0] - if language in locales_map: - return FakeTranslations(locales_map[language]) - return gettext.NullTranslations() - return _translation diff --git a/oslo_i18n/tests/test_factory.py b/oslo_i18n/tests/test_factory.py deleted file mode 100644 index 6bbe684..0000000 --- a/oslo_i18n/tests/test_factory.py +++ /dev/null @@ -1,147 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock -from oslotest import base as test_base -import six - -from oslo_i18n import _factory -from oslo_i18n import _lazy -from oslo_i18n import _message - -# magic gettext number to separate context from message -CONTEXT_SEPARATOR = _message.CONTEXT_SEPARATOR - - -class TranslatorFactoryTest(test_base.BaseTestCase): - - def setUp(self): - super(TranslatorFactoryTest, self).setUp() - # remember so we can reset to it later in case it changes - self._USE_LAZY = _lazy.USE_LAZY - - def tearDown(self): - # reset to value before test - _lazy.USE_LAZY = self._USE_LAZY - super(TranslatorFactoryTest, self).tearDown() - - def test_lazy(self): - _lazy.enable_lazy(True) - with mock.patch.object(_message, 'Message') as msg: - tf = _factory.TranslatorFactory('domain') - tf.primary('some text') - msg.assert_called_with('some text', domain='domain') - - def test_not_lazy(self): - _lazy.enable_lazy(False) - with mock.patch.object(_message, 'Message') as msg: - msg.side_effect = AssertionError('should not use Message') - tf = _factory.TranslatorFactory('domain') - tf.primary('some text') - - def test_change_lazy(self): - _lazy.enable_lazy(True) - tf = _factory.TranslatorFactory('domain') - r = tf.primary('some text') - self.assertIsInstance(r, _message.Message) - _lazy.enable_lazy(False) - r = tf.primary('some text') - self.assertNotIsInstance(r, _message.Message) - - def test_py2(self): - _lazy.enable_lazy(False) - with mock.patch.object(six, 'PY3', False): - with mock.patch('gettext.translation') as translation: - trans = mock.Mock() - translation.return_value = trans - trans.gettext.side_effect = AssertionError( - 'should have called ugettext') - tf = _factory.TranslatorFactory('domain') - tf.primary('some text') - trans.ugettext.assert_called_with('some text') - - def test_py3(self): - _lazy.enable_lazy(False) - with mock.patch.object(six, 'PY3', True): - with mock.patch('gettext.translation') as translation: - trans = mock.Mock() - translation.return_value = trans - trans.ugettext.side_effect = AssertionError( - 'should have called gettext') - tf = _factory.TranslatorFactory('domain') - tf.primary('some text') - trans.gettext.assert_called_with('some text') - - def test_log_level_domain_name(self): - with mock.patch.object(_factory.TranslatorFactory, - '_make_translation_func') as mtf: - tf = _factory.TranslatorFactory('domain') - tf._make_log_translation_func('mylevel') - mtf.assert_called_with('domain-log-mylevel') - - def test_contextual_form_py2(self): - _lazy.enable_lazy(False) - with mock.patch.object(six, 'PY3', False): - with mock.patch('gettext.translation') as translation: - trans = mock.Mock() - translation.return_value = trans - trans.gettext.side_effect = AssertionError( - 'should have called ugettext') - trans.ugettext.return_value = "some text" - tf = _factory.TranslatorFactory('domain') - tf.contextual_form('context', 'some text') - trans.ugettext.assert_called_with( - "%s%s%s" % ('context', CONTEXT_SEPARATOR, 'some text')) - - def test_contextual_form_py3(self): - _lazy.enable_lazy(False) - with mock.patch.object(six, 'PY3', True): - with mock.patch('gettext.translation') as translation: - trans = mock.Mock() - translation.return_value = trans - trans.ugettext.side_effect = AssertionError( - 'should have called gettext') - trans.gettext.return_value = "some text" - tf = _factory.TranslatorFactory('domain') - tf.contextual_form('context', 'some text') - trans.gettext.assert_called_with( - "%s%s%s" % ('context', CONTEXT_SEPARATOR, 'some text')) - - def test_plural_form_py2(self): - _lazy.enable_lazy(False) - with mock.patch.object(six, 'PY3', False): - with mock.patch('gettext.translation') as translation: - trans = mock.Mock() - translation.return_value = trans - trans.ngettext.side_effect = AssertionError( - 'should have called ungettext') - tf = _factory.TranslatorFactory('domain') - tf.plural_form('single', 'plural', 1) - trans.ungettext.assert_called_with( - 'single', 'plural', 1) - - def test_plural_form_py3(self): - _lazy.enable_lazy(False) - with mock.patch.object(six, 'PY3', True): - with mock.patch('gettext.translation') as translation: - trans = mock.Mock() - translation.return_value = trans - trans.ungettext.side_effect = AssertionError( - 'should have called ngettext') - tf = _factory.TranslatorFactory('domain') - tf.plural_form('single', 'plural', 1) - trans.ngettext.assert_called_with( - 'single', 'plural', 1) diff --git a/oslo_i18n/tests/test_fixture.py b/oslo_i18n/tests/test_fixture.py deleted file mode 100644 index 171feb0..0000000 --- a/oslo_i18n/tests/test_fixture.py +++ /dev/null @@ -1,118 +0,0 @@ -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslotest import base as test_base -import six - -import oslo_i18n -from oslo_i18n import _gettextutils -from oslo_i18n._i18n import _ -from oslo_i18n import _lazy -from oslo_i18n import _message -from oslo_i18n import _translate -from oslo_i18n import fixture - - -class TranslationFixtureTest(test_base.BaseTestCase): - - def setUp(self): - super(TranslationFixtureTest, self).setUp() - self.trans_fixture = self.useFixture(fixture.Translation()) - - def test_lazy(self): - msg = self.trans_fixture.lazy('this is a lazy message') - self.assertIsInstance(msg, _message.Message) - self.assertEqual(msg.msgid, 'this is a lazy message') - - def test_immediate(self): - msg = self.trans_fixture.immediate('this is a lazy message') - self.assertNotIsInstance(msg, _message.Message) - self.assertIsInstance(msg, six.text_type) - self.assertEqual(msg, u'this is a lazy message') - - -class ToggleLazyFixtureText(test_base.BaseTestCase): - - def test_on_on(self): - _lazy.USE_LAZY = True - f = fixture.ToggleLazy(True) - f.setUp() - self.assertTrue(_lazy.USE_LAZY) - f._restore_original() - self.assertTrue(_lazy.USE_LAZY) - - def test_on_off(self): - _lazy.USE_LAZY = True - f = fixture.ToggleLazy(False) - f.setUp() - self.assertFalse(_lazy.USE_LAZY) - f._restore_original() - self.assertTrue(_lazy.USE_LAZY) - - def test_off_on(self): - _lazy.USE_LAZY = False - f = fixture.ToggleLazy(True) - f.setUp() - self.assertTrue(_lazy.USE_LAZY) - f._restore_original() - self.assertFalse(_lazy.USE_LAZY) - - def test_off_off(self): - _lazy.USE_LAZY = False - f = fixture.ToggleLazy(False) - f.setUp() - self.assertFalse(_lazy.USE_LAZY) - f._restore_original() - self.assertFalse(_lazy.USE_LAZY) - - -_FAKE_LANG = 'en_ZZ' - - -class PrefixLazyTranslationTest(test_base.BaseTestCase): - - def test_default(self): - - # Turn lazy off to check that fixture turns it on - self.useFixture(fixture.ToggleLazy(False)) - self.useFixture(fixture.PrefixLazyTranslation()) - self.assertTrue(_lazy.USE_LAZY) - default_lang = fixture.PrefixLazyTranslation._DEFAULT_LANG - raw_id1 = 'fake msg1' - expected_msg = 'oslo_i18n/' + default_lang + ': ' + raw_id1 - msg1 = _(raw_id1) # noqa - self.assertEqual([default_lang], - _gettextutils.get_available_languages('oslo_i18n')) - self.assertEqual([default_lang], - oslo_i18n.get_available_languages('oslo_i18n')) - self.assertEqual(expected_msg, _translate.translate(msg1)) - - def test_extra_lang(self): - languages = _gettextutils.get_available_languages('oslo') - languages.append(_FAKE_LANG) - self.useFixture(fixture.PrefixLazyTranslation(languages=languages)) - raw_id1 = 'fake msg1' - expected_msg_en_US = ('oslo_i18n/' + - fixture.PrefixLazyTranslation._DEFAULT_LANG + - ': ' + raw_id1) - expected_msg_en_ZZ = 'oslo_i18n/' + _FAKE_LANG + ': ' + raw_id1 - msg1 = _(raw_id1) # noqa - self.assertEqual(languages, - _gettextutils.get_available_languages('oslo_i18n')) - self.assertEqual(languages, - oslo_i18n.get_available_languages('oslo_i18n')) - self.assertEqual(expected_msg_en_US, _translate.translate(msg1)) - self.assertEqual(expected_msg_en_ZZ, - _translate.translate(msg1, - desired_locale=_FAKE_LANG)) diff --git a/oslo_i18n/tests/test_gettextutils.py b/oslo_i18n/tests/test_gettextutils.py deleted file mode 100644 index a2531b0..0000000 --- a/oslo_i18n/tests/test_gettextutils.py +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import gettext -import logging - -from babel import localedata -import mock -from oslotest import base as test_base -from oslotest import moxstubout -import six - -from oslo_i18n import _factory -from oslo_i18n import _gettextutils -from oslo_i18n import _lazy -from oslo_i18n import _message - - -LOG = logging.getLogger(__name__) - - -class GettextTest(test_base.BaseTestCase): - - def setUp(self): - super(GettextTest, self).setUp() - moxfixture = self.useFixture(moxstubout.MoxStubout()) - self.stubs = moxfixture.stubs - self.mox = moxfixture.mox - # remember so we can reset to it later in case it changes - self._USE_LAZY = _lazy.USE_LAZY - self.t = _factory.TranslatorFactory('oslo_i18n.test') - - def tearDown(self): - # reset to value before test - _lazy.USE_LAZY = self._USE_LAZY - super(GettextTest, self).tearDown() - - def test_gettext_does_not_blow_up(self): - LOG.info(self.t.primary('test')) - - def test__gettextutils_install(self): - _gettextutils.install('blaa') - _lazy.enable_lazy(False) - self.assertTrue(isinstance(self.t.primary('A String'), - six.text_type)) - - _gettextutils.install('blaa') - _lazy.enable_lazy(True) - self.assertTrue(isinstance(self.t.primary('A Message'), - _message.Message)) - - def test_gettext_install_looks_up_localedir(self): - with mock.patch('os.environ.get') as environ_get: - with mock.patch('gettext.install'): - environ_get.return_value = '/foo/bar' - _gettextutils.install('blaa') - environ_get.assert_has_calls([mock.call('BLAA_LOCALEDIR')]) - - def test_gettext_install_updates_builtins(self): - with mock.patch('os.environ.get') as environ_get: - with mock.patch('gettext.install'): - environ_get.return_value = '/foo/bar' - if '_' in six.moves.builtins.__dict__: - del six.moves.builtins.__dict__['_'] - _gettextutils.install('blaa') - self.assertIn('_', six.moves.builtins.__dict__) - - def test_get_available_languages(self): - # All the available languages for which locale data is available - def _mock_locale_identifiers(): - # 'zh', 'zh_Hant'. 'zh_Hant_HK', 'fil' all have aliases - # missing from babel but we add them in _gettextutils, we - # test that here too - return ['zh', 'es', 'nl', 'fr', 'zh_Hant', 'zh_Hant_HK', 'fil'] - - self.stubs.Set(localedata, - 'list' if hasattr(localedata, 'list') - else 'locale_identifiers', - _mock_locale_identifiers) - - # Only the languages available for a specific translation domain - def _mock_gettext_find(domain, localedir=None, languages=None, all=0): - languages = languages or [] - if domain == 'domain_1': - return 'translation-file' if any(x in ['zh', 'es', 'fil'] - for x in languages) else None - elif domain == 'domain_2': - return 'translation-file' if any(x in ['fr', 'zh_Hant'] - for x in languages) else None - return None - self.stubs.Set(gettext, 'find', _mock_gettext_find) - - # Ensure that no domains are cached - _gettextutils._AVAILABLE_LANGUAGES = {} - - # en_US should always be available no matter the domain - # and it should also always be the first element since order matters - domain_1_languages = _gettextutils.get_available_languages('domain_1') - domain_2_languages = _gettextutils.get_available_languages('domain_2') - self.assertEqual('en_US', domain_1_languages[0]) - self.assertEqual('en_US', domain_2_languages[0]) - # The domain languages should be included after en_US with - # with their respective aliases when it applies - self.assertEqual(6, len(domain_1_languages)) - self.assertIn('zh', domain_1_languages) - self.assertIn('zh_CN', domain_1_languages) - self.assertIn('es', domain_1_languages) - self.assertIn('fil', domain_1_languages) - self.assertIn('tl_PH', domain_1_languages) - self.assertEqual(4, len(domain_2_languages)) - self.assertIn('fr', domain_2_languages) - self.assertIn('zh_Hant', domain_2_languages) - self.assertIn('zh_TW', domain_2_languages) - self.assertEqual(2, len(_gettextutils._AVAILABLE_LANGUAGES)) - # Now test an unknown domain, only en_US should be included - unknown_domain_languages = _gettextutils.get_available_languages('huh') - self.assertEqual(1, len(unknown_domain_languages)) - self.assertIn('en_US', unknown_domain_languages) diff --git a/oslo_i18n/tests/test_handler.py b/oslo_i18n/tests/test_handler.py deleted file mode 100644 index b0c678e..0000000 --- a/oslo_i18n/tests/test_handler.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import logging - -import mock -from oslotest import base as test_base -import six - -from oslo_i18n import _message -from oslo_i18n import log as i18n_log -from oslo_i18n.tests import fakes - -LOG = logging.getLogger(__name__) - - -class TranslationHandlerTestCase(test_base.BaseTestCase): - - def setUp(self): - super(TranslationHandlerTestCase, self).setUp() - - self.stream = six.StringIO() - self.destination_handler = logging.StreamHandler(self.stream) - self.translation_handler = i18n_log.TranslationHandler('zh_CN') - self.translation_handler.setTarget(self.destination_handler) - - self.logger = logging.getLogger('localehander_logger') - self.logger.setLevel(logging.DEBUG) - self.logger.addHandler(self.translation_handler) - - def test_set_formatter(self): - formatter = 'some formatter' - self.translation_handler.setFormatter(formatter) - self.assertEqual(formatter, self.translation_handler.target.formatter) - - @mock.patch('gettext.translation') - def test_emit_translated_message(self, mock_translation): - log_message = 'A message to be logged' - log_message_translation = 'A message to be logged in Chinese' - translations = {log_message: log_message_translation} - translations_map = {'zh_CN': translations} - translator = fakes.FakeTranslations.translator(translations_map) - mock_translation.side_effect = translator - - msg = _message.Message(log_message) - - self.logger.info(msg) - self.assertIn(log_message_translation, self.stream.getvalue()) - - @mock.patch('gettext.translation') - def test_emit_translated_message_with_args(self, mock_translation): - log_message = 'A message to be logged %s' - log_message_translation = 'A message to be logged in Chinese %s' - log_arg = 'Arg to be logged' - log_arg_translation = 'An arg to be logged in Chinese' - - translations = {log_message: log_message_translation, - log_arg: log_arg_translation} - translations_map = {'zh_CN': translations} - translator = fakes.FakeTranslations.translator(translations_map) - mock_translation.side_effect = translator - - msg = _message.Message(log_message) - arg = _message.Message(log_arg) - - self.logger.info(msg, arg) - self.assertIn(log_message_translation % log_arg_translation, - self.stream.getvalue()) - - @mock.patch('gettext.translation') - def test_emit_translated_message_with_named_args(self, mock_translation): - log_message = 'A message to be logged %(arg1)s $(arg2)s' - log_message_translation = 'Chinese msg to be logged %(arg1)s $(arg2)s' - log_arg_1 = 'Arg1 to be logged' - log_arg_1_translation = 'Arg1 to be logged in Chinese' - log_arg_2 = 'Arg2 to be logged' - log_arg_2_translation = 'Arg2 to be logged in Chinese' - - translations = {log_message: log_message_translation, - log_arg_1: log_arg_1_translation, - log_arg_2: log_arg_2_translation} - translations_map = {'zh_CN': translations} - translator = fakes.FakeTranslations.translator(translations_map) - mock_translation.side_effect = translator - - msg = _message.Message(log_message) - arg_1 = _message.Message(log_arg_1) - arg_2 = _message.Message(log_arg_2) - - self.logger.info(msg, {'arg1': arg_1, 'arg2': arg_2}) - translation = log_message_translation % {'arg1': log_arg_1_translation, - 'arg2': log_arg_2_translation} - self.assertIn(translation, self.stream.getvalue()) diff --git a/oslo_i18n/tests/test_lazy.py b/oslo_i18n/tests/test_lazy.py deleted file mode 100644 index 049d51a..0000000 --- a/oslo_i18n/tests/test_lazy.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslotest import base as test_base - -from oslo_i18n import _lazy - - -class LazyTest(test_base.BaseTestCase): - - def setUp(self): - super(LazyTest, self).setUp() - self._USE_LAZY = _lazy.USE_LAZY - - def tearDown(self): - _lazy.USE_LAZY = self._USE_LAZY - super(LazyTest, self).tearDown() - - def test_enable_lazy(self): - _lazy.USE_LAZY = False - _lazy.enable_lazy() - self.assertTrue(_lazy.USE_LAZY) - - def test_disable_lazy(self): - _lazy.USE_LAZY = True - _lazy.enable_lazy(False) - self.assertFalse(_lazy.USE_LAZY) diff --git a/oslo_i18n/tests/test_locale_dir_variable.py b/oslo_i18n/tests/test_locale_dir_variable.py deleted file mode 100644 index 26321c1..0000000 --- a/oslo_i18n/tests/test_locale_dir_variable.py +++ /dev/null @@ -1,32 +0,0 @@ -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslotest import base as test_base -import testscenarios.testcase - -from oslo_i18n import _locale - - -class LocaleDirVariableTest(testscenarios.testcase.WithScenarios, - test_base.BaseTestCase): - - scenarios = [ - ('simple', {'domain': 'simple', 'expected': 'SIMPLE_LOCALEDIR'}), - ('with_dot', {'domain': 'one.two', 'expected': 'ONE_TWO_LOCALEDIR'}), - ('with_dash', {'domain': 'one-two', 'expected': 'ONE_TWO_LOCALEDIR'}), - ] - - def test_make_variable_name(self): - var = _locale.get_locale_dir_variable_name(self.domain) - self.assertEqual(self.expected, var) diff --git a/oslo_i18n/tests/test_logging.py b/oslo_i18n/tests/test_logging.py deleted file mode 100644 index 07e5c71..0000000 --- a/oslo_i18n/tests/test_logging.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock -from oslotest import base as test_base - -from oslo_i18n import _factory - - -class LogLevelTranslationsTest(test_base.BaseTestCase): - - def test_info(self): - self._test('info') - - def test_warning(self): - self._test('warning') - - def test_error(self): - self._test('error') - - def test_critical(self): - self._test('critical') - - def _test(self, level): - with mock.patch.object(_factory.TranslatorFactory, - '_make_translation_func') as mtf: - tf = _factory.TranslatorFactory('domain') - getattr(tf, 'log_%s' % level) - mtf.assert_called_with('domain-log-%s' % level) diff --git a/oslo_i18n/tests/test_message.py b/oslo_i18n/tests/test_message.py deleted file mode 100644 index ba7851f..0000000 --- a/oslo_i18n/tests/test_message.py +++ /dev/null @@ -1,687 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from __future__ import unicode_literals - -import logging -import warnings - -import mock -from oslotest import base as test_base -import six -import testtools - -from oslo_i18n import _message -from oslo_i18n.tests import fakes -from oslo_i18n.tests import utils - -LOG = logging.getLogger(__name__) - - -class MessageTestCase(test_base.BaseTestCase): - """Unit tests for locale Message class.""" - - def test_message_id_and_message_text(self): - message = _message.Message('1') - self.assertEqual('1', message.msgid) - self.assertEqual('1', message) - message = _message.Message('1', msgtext='A') - self.assertEqual('1', message.msgid) - self.assertEqual('A', message) - - def test_message_is_unicode(self): - message = _message.Message('some %s') % 'message' - self.assertIsInstance(message, six.text_type) - - @mock.patch('locale.getdefaultlocale') - @mock.patch('gettext.translation') - def test_create_message_non_english_default_locale(self, - mock_translation, - mock_getdefaultlocale): - msgid = 'A message in English' - es_translation = 'A message in Spanish' - - es_translations = {msgid: es_translation} - translations_map = {'es': es_translations} - translator = fakes.FakeTranslations.translator(translations_map) - mock_translation.side_effect = translator - mock_getdefaultlocale.return_value = ('es',) - - message = _message.Message(msgid) - - # The base representation of the message is in Spanish, as well as - # the default translation, since the default locale was Spanish. - self.assertEqual(es_translation, message) - self.assertEqual(es_translation, message.translate()) - - def test_translate_returns_unicode(self): - message = _message.Message('some %s') % 'message' - self.assertIsInstance(message.translate(), six.text_type) - - def test_mod_with_named_parameters(self): - msgid = ("%(description)s\nCommand: %(cmd)s\n" - "Exit code: %(exit_code)s\nStdout: %(stdout)r\n" - "Stderr: %(stderr)r %%(something)s") - params = {'description': 'test1', - 'cmd': 'test2', - 'exit_code': 'test3', - 'stdout': 'test4', - 'stderr': 'test5', - 'something': 'trimmed'} - - result = _message.Message(msgid) % params - - expected = msgid % params - self.assertEqual(result, expected) - self.assertEqual(result.translate(), expected) - - def test_multiple_mod_with_named_parameter(self): - msgid = ("%(description)s\nCommand: %(cmd)s\n" - "Exit code: %(exit_code)s\nStdout: %(stdout)r\n" - "Stderr: %(stderr)r") - params = {'description': 'test1', - 'cmd': 'test2', - 'exit_code': 'test3', - 'stdout': 'test4', - 'stderr': 'test5'} - - # Run string interpolation the first time to make a new Message - first = _message.Message(msgid) % params - - # Run string interpolation on the new Message, to replicate - # one of the error paths with some Exception classes we've - # implemented in OpenStack. We should receive a second Message - # object, but the translation results should be the same. - # - # The production code that triggers this problem does something - # like: - # - # msg = _('there was a problem %(name)s') % {'name': 'some value'} - # LOG.error(msg) - # raise BadExceptionClass(msg) - # - # where BadExceptionClass does something like: - # - # class BadExceptionClass(Exception): - # def __init__(self, msg, **kwds): - # super(BadExceptionClass, self).__init__(msg % kwds) - # - expected = first % {} - - # Base message id should be the same - self.assertEqual(first.msgid, expected.msgid) - - # Preserved arguments should be the same - self.assertEqual(first.params, expected.params) - - # Should have different objects - self.assertIsNot(expected, first) - - # Final translations should be the same - self.assertEqual(expected.translate(), first.translate()) - - def test_mod_with_named_parameters_no_space(self): - msgid = ("Request: %(method)s http://%(server)s:" - "%(port)s%(url)s with headers %(headers)s") - params = {'method': 'POST', - 'server': 'test1', - 'port': 1234, - 'url': 'test2', - 'headers': {'h1': 'val1'}} - - result = _message.Message(msgid) % params - - expected = msgid % params - self.assertEqual(result, expected) - self.assertEqual(result.translate(), expected) - - def test_mod_with_dict_parameter(self): - msgid = "Test that we can inject a dictionary %s" - params = {'description': 'test1'} - - result = _message.Message(msgid) % params - - expected = msgid % params - self.assertEqual(expected, result) - self.assertEqual(expected, result.translate()) - - def test_mod_with_wrong_field_type_in_trans(self): - msgid = "Correct type %(arg1)s" - params = {'arg1': 'test1'} - with mock.patch('gettext.translation') as trans: - # Set up ugettext to return the original message with the - # correct format string. - trans.return_value.ugettext.return_value = msgid - # Build a message and give it some parameters. - result = _message.Message(msgid) % params - # Now set up ugettext to return the translated version of - # the original message, with a bad format string. - wrong_type = u'Wrong type %(arg1)d' - if six.PY3: - trans.return_value.gettext.return_value = wrong_type - else: - trans.return_value.ugettext.return_value = wrong_type - trans_result = result.translate() - expected = msgid % params - self.assertEqual(expected, trans_result) - - def test_mod_with_wrong_field_type(self): - msgid = "Test that we handle unused args %(arg1)d" - params = {'arg1': 'test1'} - - with testtools.ExpectedException(TypeError): - _message.Message(msgid) % params - - def test_mod_with_missing_arg(self): - msgid = "Test that we handle missing args %(arg1)s %(arg2)s" - params = {'arg1': 'test1'} - - with testtools.ExpectedException(KeyError, '.*arg2.*'): - _message.Message(msgid) % params - - def test_mod_with_integer_parameters(self): - msgid = "Some string with params: %d" - params = [0, 1, 10, 24124] - - messages = [] - results = [] - for param in params: - messages.append(msgid % param) - results.append(_message.Message(msgid) % param) - - for message, result in zip(messages, results): - self.assertEqual(type(result), _message.Message) - self.assertEqual(result.translate(), message) - - # simulate writing out as string - result_str = '%s' % result.translate() - self.assertEqual(result_str, message) - self.assertEqual(result, message) - - def test_mod_copies_parameters(self): - msgid = "Found object: %(current_value)s" - changing_dict = {'current_value': 1} - # A message created with some params - result = _message.Message(msgid) % changing_dict - # The parameters may change - changing_dict['current_value'] = 2 - # Even if the param changes when the message is - # translated it should use the original param - self.assertEqual(result.translate(), 'Found object: 1') - - def test_mod_deep_copies_parameters(self): - msgid = "Found list: %(current_list)s" - changing_list = list([1, 2, 3]) - params = {'current_list': changing_list} - # Apply the params - result = _message.Message(msgid) % params - # Change the list - changing_list.append(4) - # Even though the list changed the message - # translation should use the original list - self.assertEqual(result.translate(), "Found list: [1, 2, 3]") - - def test_mod_deep_copies_param_nodeep_param(self): - msgid = "Value: %s" - params = utils.NoDeepCopyObject(5) - # Apply the params - result = _message.Message(msgid) % params - self.assertEqual(result.translate(), "Value: 5") - - def test_mod_deep_copies_param_nodeep_dict(self): - msgid = "Values: %(val1)s %(val2)s" - params = {'val1': 1, 'val2': utils.NoDeepCopyObject(2)} - # Apply the params - result = _message.Message(msgid) % params - self.assertEqual(result.translate(), "Values: 1 2") - - # Apply again to make sure other path works as well - params = {'val1': 3, 'val2': utils.NoDeepCopyObject(4)} - result = _message.Message(msgid) % params - self.assertEqual(result.translate(), "Values: 3 4") - - def test_mod_returns_a_copy(self): - msgid = "Some msgid string: %(test1)s %(test2)s" - message = _message.Message(msgid) - m1 = message % {'test1': 'foo', 'test2': 'bar'} - m2 = message % {'test1': 'foo2', 'test2': 'bar2'} - - self.assertIsNot(message, m1) - self.assertIsNot(message, m2) - self.assertEqual(m1.translate(), - msgid % {'test1': 'foo', 'test2': 'bar'}) - self.assertEqual(m2.translate(), - msgid % {'test1': 'foo2', 'test2': 'bar2'}) - - def test_mod_with_none_parameter(self): - msgid = "Some string with params: %s" - message = _message.Message(msgid) % None - self.assertEqual(msgid % None, message) - self.assertEqual(msgid % None, message.translate()) - - def test_mod_with_missing_parameters(self): - msgid = "Some string with params: %s %s" - test_me = lambda: _message.Message(msgid) % 'just one' - # Just like with strings missing parameters raise TypeError - self.assertRaises(TypeError, test_me) - - def test_mod_with_extra_parameters(self): - msgid = "Some string with params: %(param1)s %(param2)s" - params = {'param1': 'test', - 'param2': 'test2', - 'param3': 'notinstring'} - - result = _message.Message(msgid) % params - - expected = msgid % params - self.assertEqual(result, expected) - self.assertEqual(result.translate(), expected) - - # Make sure unused params still there - self.assertEqual(result.params.keys(), params.keys()) - - def test_add_disabled(self): - msgid = "A message" - test_me = lambda: _message.Message(msgid) + ' some string' - self.assertRaises(TypeError, test_me) - - def test_radd_disabled(self): - msgid = "A message" - test_me = lambda: utils.SomeObject('test') + _message.Message(msgid) - self.assertRaises(TypeError, test_me) - - @mock.patch('gettext.translation') - def test_translate(self, mock_translation): - en_message = 'A message in the default locale' - es_translation = 'A message in Spanish' - message = _message.Message(en_message) - - es_translations = {en_message: es_translation} - translations_map = {'es': es_translations} - translator = fakes.FakeTranslations.translator(translations_map) - mock_translation.side_effect = translator - - self.assertEqual(es_translation, message.translate('es')) - - @mock.patch('gettext.translation') - def test_translate_message_from_unicoded_object(self, mock_translation): - en_message = 'A message in the default locale' - es_translation = 'A message in Spanish' - message = _message.Message(en_message) - es_translations = {en_message: es_translation} - translations_map = {'es': es_translations} - translator = fakes.FakeTranslations.translator(translations_map) - mock_translation.side_effect = translator - - # Here we are not testing the Message object directly but the result - # of unicoding() an object whose unicode representation is a Message - obj = utils.SomeObject(message) - unicoded_obj = six.text_type(obj) - - self.assertEqual(es_translation, unicoded_obj.translate('es')) - - @mock.patch('gettext.translation') - def test_translate_multiple_languages(self, mock_translation): - en_message = 'A message in the default locale' - es_translation = 'A message in Spanish' - zh_translation = 'A message in Chinese' - message = _message.Message(en_message) - - es_translations = {en_message: es_translation} - zh_translations = {en_message: zh_translation} - translations_map = {'es': es_translations, - 'zh': zh_translations} - translator = fakes.FakeTranslations.translator(translations_map) - mock_translation.side_effect = translator - - self.assertEqual(es_translation, message.translate('es')) - self.assertEqual(zh_translation, message.translate('zh')) - self.assertEqual(en_message, message.translate(None)) - self.assertEqual(en_message, message.translate('en')) - self.assertEqual(en_message, message.translate('XX')) - - @mock.patch('gettext.translation') - def test_translate_message_with_param(self, mock_translation): - message_with_params = 'A message: %s' - es_translation = 'A message in Spanish: %s' - param = 'A Message param' - - translations = {message_with_params: es_translation} - translator = fakes.FakeTranslations.translator({'es': translations}) - mock_translation.side_effect = translator - - msg = _message.Message(message_with_params) - msg = msg % param - - default_translation = message_with_params % param - expected_translation = es_translation % param - self.assertEqual(expected_translation, msg.translate('es')) - self.assertEqual(default_translation, msg.translate('XX')) - - @mock.patch('gettext.translation') - @mock.patch('oslo_i18n._message.LOG') - def test_translate_message_bad_translation(self, - mock_log, - mock_translation): - message_with_params = 'A message: %s' - es_translation = 'A message in Spanish: %s %s' - param = 'A Message param' - - translations = {message_with_params: es_translation} - translator = fakes.FakeTranslations.translator({'es': translations}) - mock_translation.side_effect = translator - - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - msg = _message.Message(message_with_params) - msg = msg % param - default_translation = message_with_params % param - - self.assertEqual(default_translation, msg.translate('es')) - - self.assertEqual(1, len(w)) - # Note(gibi): in python 3.4 str.__repr__ does not put the unicode - # marker 'u' in front of the string representations so the test - # removes that to have the same result in python 2.7 and 3.4 - self.assertEqual("Failed to insert replacement values into " - "translated message A message in Spanish: %s %s " - "(Original: 'A message: %s'): " - "not enough arguments for format string", - str(w[0].message).replace("u'", "'")) - - mock_log.debug.assert_called_with(('Failed to insert replacement ' - 'values into translated message ' - '%s (Original: %r): %s'), - es_translation, - message_with_params, - mock.ANY) - - @mock.patch('gettext.translation') - @mock.patch('locale.getdefaultlocale', return_value=('es', '')) - @mock.patch('oslo_i18n._message.LOG') - def test_translate_message_bad_default_translation(self, - mock_log, - mock_local, - mock_translation): - message_with_params = 'A message: %s' - es_translation = 'A message in Spanish: %s %s' - param = 'A Message param' - - translations = {message_with_params: es_translation} - translator = fakes.FakeTranslations.translator({'es': translations}) - mock_translation.side_effect = translator - - msg = _message.Message(message_with_params) - - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - msg = msg % param - self.assertEqual(1, len(w)) - # Note(gibi): in python 3.4 str.__repr__ does not put the unicode - # marker 'u' in front of the string representations so the test - # removes that to have the same result in python 2.7 and 3.4 - self.assertEqual("Failed to insert replacement values into " - "translated message A message in Spanish: %s %s " - "(Original: 'A message: %s'): " - "not enough arguments for format string", - str(w[0].message).replace("u'", "'")) - - mock_log.debug.assert_called_with(('Failed to insert replacement ' - 'values into translated message ' - '%s (Original: %r): %s'), - es_translation, - message_with_params, - mock.ANY) - mock_log.reset_mock() - - default_translation = message_with_params % param - self.assertEqual(default_translation, msg) - self.assertFalse(mock_log.warning.called) - - @mock.patch('gettext.translation') - def test_translate_message_with_object_param(self, mock_translation): - message_with_params = 'A message: %s' - es_translation = 'A message in Spanish: %s' - param = 'A Message param' - param_translation = 'A Message param in Spanish' - - translations = {message_with_params: es_translation, - param: param_translation} - translator = fakes.FakeTranslations.translator({'es': translations}) - mock_translation.side_effect = translator - - msg = _message.Message(message_with_params) - param_msg = _message.Message(param) - - # Here we are testing translation of a Message with another object - # that can be translated via its unicode() representation, this is - # very common for instance when modding an Exception with a Message - obj = utils.SomeObject(param_msg) - msg = msg % obj - - default_translation = message_with_params % param - expected_translation = es_translation % param_translation - - self.assertEqual(expected_translation, msg.translate('es')) - self.assertEqual(default_translation, msg.translate('XX')) - - @mock.patch('gettext.translation') - def test_translate_message_with_param_from_unicoded_obj(self, - mock_translation): - message_with_params = 'A message: %s' - es_translation = 'A message in Spanish: %s' - param = 'A Message param' - - translations = {message_with_params: es_translation} - translator = fakes.FakeTranslations.translator({'es': translations}) - mock_translation.side_effect = translator - - msg = _message.Message(message_with_params) - msg = msg % param - - default_translation = message_with_params % param - expected_translation = es_translation % param - - obj = utils.SomeObject(msg) - unicoded_obj = six.text_type(obj) - - self.assertEqual(expected_translation, unicoded_obj.translate('es')) - self.assertEqual(default_translation, unicoded_obj.translate('XX')) - - @mock.patch('gettext.translation') - def test_translate_message_with_message_parameter(self, mock_translation): - message_with_params = 'A message with param: %s' - es_translation = 'A message with param in Spanish: %s' - message_param = 'A message param' - es_param_translation = 'A message param in Spanish' - - translations = {message_with_params: es_translation, - message_param: es_param_translation} - translator = fakes.FakeTranslations.translator({'es': translations}) - mock_translation.side_effect = translator - - msg = _message.Message(message_with_params) - msg_param = _message.Message(message_param) - msg = msg % msg_param - - default_translation = message_with_params % message_param - expected_translation = es_translation % es_param_translation - self.assertEqual(expected_translation, msg.translate('es')) - self.assertEqual(default_translation, msg.translate('XX')) - - @mock.patch('gettext.translation') - def test_translate_message_with_message_parameters(self, mock_translation): - message_with_params = 'A message with params: %s %s' - es_translation = 'A message with params in Spanish: %s %s' - message_param = 'A message param' - es_param_translation = 'A message param in Spanish' - another_message_param = 'Another message param' - another_es_param_translation = 'Another message param in Spanish' - - translations = {message_with_params: es_translation, - message_param: es_param_translation, - another_message_param: another_es_param_translation} - translator = fakes.FakeTranslations.translator({'es': translations}) - mock_translation.side_effect = translator - - msg = _message.Message(message_with_params) - param_1 = _message.Message(message_param) - param_2 = _message.Message(another_message_param) - msg = msg % (param_1, param_2) - - default_translation = message_with_params % (message_param, - another_message_param) - expected_translation = es_translation % (es_param_translation, - another_es_param_translation) - self.assertEqual(expected_translation, msg.translate('es')) - self.assertEqual(default_translation, msg.translate('XX')) - - @mock.patch('gettext.translation') - def test_translate_message_with_named_parameters(self, mock_translation): - message_with_params = 'A message with params: %(param)s' - es_translation = 'A message with params in Spanish: %(param)s' - message_param = 'A Message param' - es_param_translation = 'A message param in Spanish' - - translations = {message_with_params: es_translation, - message_param: es_param_translation} - translator = fakes.FakeTranslations.translator({'es': translations}) - mock_translation.side_effect = translator - - msg = _message.Message(message_with_params) - msg_param = _message.Message(message_param) - msg = msg % {'param': msg_param} - - default_translation = message_with_params % {'param': message_param} - expected_translation = es_translation % {'param': es_param_translation} - self.assertEqual(expected_translation, msg.translate('es')) - self.assertEqual(default_translation, msg.translate('XX')) - - @mock.patch('locale.getdefaultlocale') - @mock.patch('gettext.translation') - def test_translate_message_non_default_locale(self, - mock_translation, - mock_getdefaultlocale): - message_with_params = 'A message with params: %(param)s' - es_translation = 'A message with params in Spanish: %(param)s' - zh_translation = 'A message with params in Chinese: %(param)s' - fr_translation = 'A message with params in French: %(param)s' - - message_param = 'A Message param' - es_param_translation = 'A message param in Spanish' - zh_param_translation = 'A message param in Chinese' - fr_param_translation = 'A message param in French' - - es_translations = {message_with_params: es_translation, - message_param: es_param_translation} - zh_translations = {message_with_params: zh_translation, - message_param: zh_param_translation} - fr_translations = {message_with_params: fr_translation, - message_param: fr_param_translation} - - translator = fakes.FakeTranslations.translator({'es': es_translations, - 'zh': zh_translations, - 'fr': fr_translations}) - mock_translation.side_effect = translator - mock_getdefaultlocale.return_value = ('es',) - - msg = _message.Message(message_with_params) - msg_param = _message.Message(message_param) - msg = msg % {'param': msg_param} - - es_translation = es_translation % {'param': es_param_translation} - zh_translation = zh_translation % {'param': zh_param_translation} - fr_translation = fr_translation % {'param': fr_param_translation} - - # Because sys.getdefaultlocale() was Spanish, - # the default translation will be to Spanish - self.assertEqual(es_translation, msg) - self.assertEqual(es_translation, msg.translate()) - self.assertEqual(es_translation, msg.translate('es')) - - # Translation into other locales still works - self.assertEqual(zh_translation, msg.translate('zh')) - self.assertEqual(fr_translation, msg.translate('fr')) - - -class TranslateMsgidTest(test_base.BaseTestCase): - - @mock.patch('gettext.translation') - def test_contextual(self, translation): - lang = mock.Mock() - translation.return_value = lang - trans = mock.Mock() - trans.return_value = 'translated' - lang.gettext = trans - lang.ugettext = trans - result = _message.Message._translate_msgid( - ('context', 'message'), - domain='domain', - has_contextual_form=True, - has_plural_form=False, - ) - self.assertEqual('translated', result) - trans.assert_called_with( - 'context' + _message.CONTEXT_SEPARATOR + 'message' - ) - - @mock.patch('gettext.translation') - def test_contextual_untranslatable(self, translation): - msg_with_context = 'context' + _message.CONTEXT_SEPARATOR + 'message' - lang = mock.Mock() - translation.return_value = lang - trans = mock.Mock() - trans.return_value = msg_with_context - lang.gettext = trans - lang.ugettext = trans - result = _message.Message._translate_msgid( - ('context', 'message'), - domain='domain', - has_contextual_form=True, - has_plural_form=False, - ) - self.assertEqual('message', result) - trans.assert_called_with(msg_with_context) - - @mock.patch('gettext.translation') - def test_plural(self, translation): - lang = mock.Mock() - translation.return_value = lang - trans = mock.Mock() - trans.return_value = 'translated' - lang.ngettext = trans - lang.ungettext = trans - result = _message.Message._translate_msgid( - ('single', 'plural', -1), - domain='domain', - has_contextual_form=False, - has_plural_form=True, - ) - self.assertEqual('translated', result) - trans.assert_called_with( - 'single', 'plural', -1, - ) - - @mock.patch('gettext.translation') - def test_contextual_and_plural(self, translation): - self.assertRaises( - ValueError, - _message.Message._translate_msgid, - 'nothing', - domain='domain', - has_contextual_form=True, - has_plural_form=True, - ) diff --git a/oslo_i18n/tests/test_public_api.py b/oslo_i18n/tests/test_public_api.py deleted file mode 100644 index d419105..0000000 --- a/oslo_i18n/tests/test_public_api.py +++ /dev/null @@ -1,44 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -"""A few tests that use the public API to ensure the imports work. -""" - -import unittest - -import mock - -import oslo_i18n -from oslo_i18n import _lazy - - -class PublicAPITest(unittest.TestCase): - - def test_create_factory(self): - oslo_i18n.TranslatorFactory('domain') - - def test_install(self): - with mock.patch('six.moves.builtins'): - oslo_i18n.install('domain') - - def test_get_available_languages(self): - oslo_i18n.get_available_languages('domains') - - def test_toggle_lazy(self): - original = _lazy.USE_LAZY - try: - oslo_i18n.enable_lazy(True) - oslo_i18n.enable_lazy(False) - finally: - oslo_i18n.enable_lazy(original) - - def test_translate(self): - oslo_i18n.translate(u'string') diff --git a/oslo_i18n/tests/test_translate.py b/oslo_i18n/tests/test_translate.py deleted file mode 100644 index 335b28c..0000000 --- a/oslo_i18n/tests/test_translate.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2012 Red Hat, Inc. -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from __future__ import unicode_literals - -import mock -from oslotest import base as test_base - -from oslo_i18n import _message -from oslo_i18n import _translate -from oslo_i18n.tests import fakes -from oslo_i18n.tests import utils - - -class TranslateTest(test_base.BaseTestCase): - - @mock.patch('gettext.translation') - def test_translate(self, mock_translation): - en_message = 'A message in the default locale' - es_translation = 'A message in Spanish' - message = _message.Message(en_message) - - es_translations = {en_message: es_translation} - translations_map = {'es': es_translations} - translator = fakes.FakeTranslations.translator(translations_map) - mock_translation.side_effect = translator - - # translate() works on msgs and on objects whose unicode reps are msgs - obj = utils.SomeObject(message) - self.assertEqual(es_translation, _translate.translate(message, 'es')) - self.assertEqual(es_translation, _translate.translate(obj, 'es')) diff --git a/oslo_i18n/tests/utils.py b/oslo_i18n/tests/utils.py deleted file mode 100644 index a6ad6c3..0000000 --- a/oslo_i18n/tests/utils.py +++ /dev/null @@ -1,42 +0,0 @@ -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import six - - -class SomeObject(object): - - def __init__(self, message): - self.message = message - - def __unicode__(self): - return self.message - # alias for Python 3 - __str__ = __unicode__ - - -class NoDeepCopyObject(object): - - def __init__(self, value): - self.value = value - - if six.PY3: - def __str__(self): - return str(self.value) - else: - def __unicode__(self): - return unicode(self.value) - - def __deepcopy__(self, memo): - raise TypeError('Deep Copy not supported') diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 8340453..0000000 --- a/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. - -pbr>=1.6 # Apache-2.0 -Babel>=2.3.4 # BSD -six>=1.9.0 # MIT diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index eacf7c9..0000000 --- a/setup.cfg +++ /dev/null @@ -1,51 +0,0 @@ -[metadata] -name = oslo.i18n -summary = Oslo i18n library -description-file = - README.rst -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = http://wiki.openstack.org/wiki/Oslo#oslo.i18n -classifier = - Environment :: OpenStack - Intended Audience :: Information Technology - Intended Audience :: System Administrators - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.4 - -[files] -packages = - oslo_i18n - -[build_sphinx] -source-dir = doc/source -build-dir = doc/build -all_files = 1 - -[upload_sphinx] -upload-dir = doc/build/html - -[compile_catalog] -directory = oslo_i18n/locale -domain = oslo_i18n - -[update_catalog] -domain = oslo_i18n -output_dir = oslo_i18n/locale -input_file = oslo_i18n/locale/oslo_i18n.pot - -[extract_messages] -keywords = _ gettext ngettext l_ lazy_gettext _C:1c,2 _P:1,2 -mapping_file = babel.cfg -output_file = oslo_i18n/locale/oslo_i18n.pot - -[pbr] -warnerrors = True - -[wheel] -universal = 1 diff --git a/setup.py b/setup.py deleted file mode 100644 index 782bb21..0000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=1.8'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 80bdbbb..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,15 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -hacking<0.11,>=0.10.0 - - -sphinx!=1.3b1,<1.3,>=1.2.1 # BSD -oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0 - -mock>=2.0 # BSD -oslotest>=1.10.0 # Apache-2.0 -coverage>=3.6 # Apache-2.0 - -# for pre-release tests -oslo.config>=3.12.0 # Apache-2.0 diff --git a/tox.ini b/tox.ini deleted file mode 100644 index b4c7c32..0000000 --- a/tox.ini +++ /dev/null @@ -1,38 +0,0 @@ -[tox] -minversion = 1.6 -envlist = py34,py27,pep8 - -[testenv] -deps = -r{toxinidir}/test-requirements.txt -commands = python setup.py testr --slowest --testr-args='{posargs}' - -[testenv:pep8] -commands = flake8 - -[testenv:venv] -commands = {posargs} - -[testenv:docs] -commands = python setup.py build_sphinx - -[testenv:cover] -commands = python setup.py test --coverage --coverage-package-name=oslo_i18n --testr-args='{posargs}' - -[flake8] -# E123, E125 skipped as they are invalid PEP-8. - -show-source = True -ignore = E123,E125 -exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,__init__.py - -[hacking] -import_exceptions = - oslo_i18n._i18n._ - -[testenv:pip-missing-reqs] -# do not install test-requirements as that will pollute the virtualenv for -# determining missing packages -# this also means that pip-missing-reqs must be installed separately, outside -# of the requirements.txt files -deps = pip_missing_reqs -commands = pip-missing-reqs -d --ignore-module=oslo_i18n* --ignore-file=oslo_i18n/tests/* --ignore-file=tests/ oslo_i18n