oslo.i18n-3.19.0/0000775000175100017510000000000013211222152013351 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/LICENSE0000666000175100017510000002363613211221721014373 0ustar zuulzuul00000000000000 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. oslo.i18n-3.19.0/ChangeLog0000664000175100017510000002456113211222151015132 0ustar zuulzuul00000000000000CHANGES ======= 3.19.0 ------ * Remove -U from pip install * Avoid tox\_install.sh for constraints support * Updated from global requirements * Remove setting of version/release from releasenotes * Updated from global requirements * Imported Translations from Zanata * Updated from global requirements 3.18.0 ------ * Updated from global requirements * Updated from global requirements * Imported Translations from Zanata * Update reno for stable/pike * Updated from global requirements 3.17.0 ------ * Imported Translations from Zanata * Update URLs in documents according to document migration 3.16.0 ------ * switch from oslosphinx to openstackdocstheme * turn on warning-is-error in doc build * rearrange the documentation to fit into the new standard layout * Updated from global requirements * Enable some off-by-default checks * Updated from global requirements * Updated from global requirements * Updated from global requirements 3.15.3 ------ * Revert "Remove Babel as a runtime requirement" 3.15.2 ------ * Updated from global requirements * Remove Babel as a runtime requirement 3.15.1 ------ * Updated from global requirements * Updated from global requirements * Updated from global requirements * Check reStructuredText documents for common style issues 3.15.0 ------ * add notes about skipping log translation setup * Updated from global requirements 3.14.0 ------ * Python 3.5 is added 3.13.0 ------ * Updated from global requirements * [Fix gate]Update test requirement * Fix wrong response with language zh-TW * Updated from global requirements * Update reno for stable/ocata 3.12.0 ------ * Add Constraints support * Show team and repo badges on README * Replace six.iteritems() with .items() 3.11.0 ------ * Updated from global requirements * Updated from global requirements * Updated from global requirements * Add reno for release notes management * Add missing dependency testscenarios * Typo fix in oslo.i18n * Changed the home-page link * Add docs on how to display translated strings in your app 3.10.0 ------ * Updated from global requirements 3.9.0 ----- * Updated from global requirements * Fix parameters of assertEqual are misplaced 3.8.0 ----- * Updated from global requirements * Don't include openstack/common in flake8 exclude list * Updated from global requirements 3.7.0 ----- * Imported Translations from Zanata * Updated from global requirements 3.6.0 ----- * Updated from global requirements * Updated from global requirements * Better isolate tests and fixtures from environment * Updated from global requirements 3.4.0 ----- * Imported Translations from Zanata 3.3.0 ----- * Update translation setup * Updated from global requirements * Imported Translations from Zanata * Updated from global requirements 3.2.0 ----- * Updated from global requirements * add versionadded designations to newer functions * doc: contextual/plural translation requires oslo.i18n >=2.1.0 * Trival: Remove 'MANIFEST.in' 3.1.0 ----- * [doc] Update \_i18n.py example to pass pep8 * Add missing blank in usage.rst * Remove Python 2.6 workround for logging * Drop python 2.6 support 3.0.0 ----- * Updated from global requirements * Remove python 2.6 classifier * Remove python 2.6 and cleanup tox.ini * Improved integration module documentation * Updated from global requirements * Imported Translations from Zanata 2.7.0 ----- * Fix coverage configuration and execution * No need for Oslo Incubator Sync * Enhance the formatting error robustness patch * Imported Translations from Zanata * Move 'history' -> release notes section * Add shields.io version/downloads links/badges into README.rst * Change ignore-errors to ignore\_errors * Added the home-page value with Oslo wiki * Updated from global requirements 2.6.0 ----- * Updated from global requirements * Updated from global requirements 2.5.0 ----- * Trap formatting errors 2.4.0 ----- * Imported Translations from Transifex * Updated from global requirements * Imported Translations from Transifex * Updated from global requirements * Clean up \_translate\_msgid logic a bit 2.3.0 ----- * Imported Translations from Transifex * Updated from global requirements 2.2.0 ----- * Imported Translations from Transifex * Updated from global requirements * Updated from global requirements * Updated from global requirements * Updated from global requirements * Fix mock use for 1.1.0 * Add requirements for pre-release test scripts * Imported Translations from Transifex 2.1.0 ----- * Only define CONTEXT\_SEPARATOR once * Support contextual and plural form of gettext functions * Imported Translations from Transifex * clarify translation policy * Add tox target to find missing requirements * Imported Translations from Transifex 2.0.0 ----- * Updated from global requirements * Updated from global requirements * Remove oslo namespace package 1.7.0 ----- * Advertise support for Python3.4 / Remove support for Python 3.3 * Updated from global requirements * Misplaced parenthesis causing confusion * Remove run\_cross\_tests.sh * Imported Translations from Transifex 1.6.0 ----- * Uncap library requirements for liberty * Standardize setup.cfg summary for oslo libs * Updated from global requirements * Move to hacking 0.10 * Update guideline doc of multiple use msg case 1.5.0 ----- * Updated from global requirements 1.4.0 ----- * Add test fixture to prefix lazily translated messages 1.3.1 ----- * Clear global cache in test\_get\_available\_languages * Make setup.cfg packages include oslo.i18n * Improve fixture documentation 1.3.0 ----- * Add a fixture to let tests manage the lazy flag * Fix the link to the bug tracker in the README 1.2.0 ----- * Correct the translation domain for loading messages * Move out of the oslo namespace package * Workflow documentation is now in infra-manual * Force code sample to be treated as python 1.1.0 ----- * Imported Translations from Transifex * Add note for integration modules in libraries * Activate pep8 check that \_ is imported * Add pbr to installation requirements * Updated from global requirements * Updated from global requirements * Remove extraneous vim editor configuration comments * Make clear in docs to use \_LE() when using LOG.exception() * Support building wheels (PEP-427) * Imported Translations from Transifex * Fix coverage testing * Imported Translations from Transifex * Use same indentation in doc/source/usage * Imported Translations from Transifex * Imported Translations from Transifex * Updated from global requirements * Remove unused/mutable default args * Fixes a small syntax error in the doc examples 1.0.0 ----- * Add missing six dependency 0.3.0 ----- * Imported Translations from Transifex * Work toward Python 3.4 support and testing * Updated from global requirements * Imported Translations from Transifex * Document how to add import exceptions 0.2.0 ----- * Add a test fixture for translatable strings * Imported Translations from Transifex * Remove mention of Message objects from public docs * Add Changelog to the documentation 0.1.0 ----- * Shift public API to top level package * Add links to policy discussions * Improve initial documentation * Update sphinx and hacking requirements * Fix import grouping in tests * Build locale dir env var name consistently * Updated from global requirements * Remove Babel version workaround code * Trivial refactors for gettextutils * Setup for translation * Update the public API of the library * Check the lazy flag at runtime * Handle . and - in translation domains * Split up monolithic test file * Updated from global requirements * Fix up usage instructions * fix docstring for fakes module * Update default tox settings * update .gitreview * update tests for python 3 * sync cross-test script from incubator * pep8 fixes from import * update .gitignore with new lib name * Make unit tests pass * initial export with graduate.sh * Add API for creating translation functions * Use oslotest instead of common test module * Fix test\_gettextutils on Python 3 * Fix gettextutil.Message handling of deep copy failures * Change lazy translation to retain complete dict * Remove requirements.txt from .gitignore * Add etc/openstack.conf.sample to .gitignore * Add support for translating log levels separately * Fix E501 in individual openstack projects * Fix test method use * Make Message keep string interpolation args * Add support for locales missing from babel * Allow the Message class to have non-English default locales * Implementation of translation log handler * Use hacking import\_exceptions for gettextutils.\_ * Translation Message improvements * Fix violations of H302:import only modules * Fixed misspellings of common words * Trivial: Make vertical white space after license header consistent * Remove vim header * Use six.text\_type instead of unicode function in tests * Fix typos in oslo * Adjust import order according to PEP8 imports rule * Replace assertEquals with assertEqual * When translating if no locale is given use default locale * Type check for Message param to avoid AttributeError * gettextutils: port to Python 3 * Translate all substitution elements of a Message object * python3: Fix UserString import * Replace using tests.utils part2 * Enable multiple translation domains for gettextutils * Bump hacking to 0.7.0 * Allow mapping \_ to lazy gettext path * Fix Message format-string parsing * Add common methods required to allow translation of REST API responses * Add eclipse project files to .gitignore * Add more robust gettext interpolation handling * Add .testrepository to .gitignore * python3: Add basic python3 compatibility * Enable hacking H404 test * Add basic lazy gettext implementation * Ignore backup files in .gitignore * Support overriding oslo localedir too * Add a gettextutils.install() helper function * gettextutils: fix translation domain * Fix Copyright Headers - Rename LLC to Foundation * Add join\_consumer\_pool() to RPC connections * Replace direct use of testtools BaseTestCase * Use testtools as test base class * Fixes import order errors * Add common base weigher/weigher handler for filter scheduler * updating sphinx documentation * Correcting openstack-common mv to oslo-incubator * Update .gitreview for oslo * .gitignore updates for generated files * Add gettext support * Updated tox config for multi-python testing * Added .gitreview file * ignore cover's html directory * Rajaram/Vinkesh|increased tests for Request and Response serializers * Rajaram/Vinkesh|Added nova's serializaiton classes into common * Initial skeleton project oslo.i18n-3.19.0/setup.cfg0000666000175100017510000000223213211222152015173 0ustar zuulzuul00000000000000[metadata] name = oslo.i18n summary = Oslo i18n library description-file = README.rst author = OpenStack author-email = openstack-dev@lists.openstack.org home-page = https://docs.openstack.org/oslo.i18n/latest 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.5 [files] packages = oslo_i18n [build_sphinx] source-dir = doc/source build-dir = doc/build all_files = 1 warning-is-error = 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 [wheel] universal = 1 [egg_info] tag_build = tag_date = 0 oslo.i18n-3.19.0/AUTHORS0000664000175100017510000000467013211222151014427 0ustar zuulzuul00000000000000Akihiro Motoki Akihiro Motoki Alessio Ababilov Anderson Mesquita Andreas Jaeger Andreas Jaeger Andrey Kurilin Balazs Gibizer Ben Nemec Bo Chi Brant Knudson Chang Bo Guo ChangBo Guo(gcb) Christian Berendt Chuck Short Dan Prince Davanum Srinivas Davanum Srinivas David Stanek Dina Belova Doug Hellmann Doug Hellmann Flavio Percoco James Carey Jason Kölker Jay Pipes Jeremy Stanley Joe Gordon Joe Heck John Warren Joshua Harlow Joshua Harlow Juan Antonio Osorio Julien Danjou Luis A. Garcia Luong Anh Tuan Mark McLoughlin Mathew Odden Matt Odden Monty Taylor Nikhil Manchanda Noorul Islam K M OpenStack Release Bot Peng Wu Rajaram Mallya Ronald Bradford Rosario Di Somma Russell Bryant Sean McGinnis Sergey Kraynev Steve Martinelli Tony Breeds Victor Sergeyev Victor Stinner WangBinbin ZhiQiang Fan Zhiteng Huang ZhongShengping Zhongyue Luo Zuul howardlee kavithahr lingyongxu melissaml ricolin venkatamahesh yanheven oslo.i18n-3.19.0/.mailmap0000666000175100017510000000013013211221721014767 0ustar zuulzuul00000000000000# Format is: # # oslo.i18n-3.19.0/tox.ini0000666000175100017510000000272313211221721014673 0ustar zuulzuul00000000000000[tox] minversion = 2.0 envlist = py35,py27,pep8 [testenv] install_command = pip install {opts} {packages} deps = -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} -r{toxinidir}/test-requirements.txt -r{toxinidir}/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 # H106: Don’t put vim configuration in source files # H203: Use assertIs(Not)None to check for None enable-extensions=H106,H203 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 [testenv:releasenotes] commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html oslo.i18n-3.19.0/test-requirements.txt0000666000175100017510000000100413211221721017610 0ustar zuulzuul00000000000000# 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.13.0,<0.14,>=0.12.0 # Apache-2.0 sphinx>=1.6.2 # BSD openstackdocstheme>=1.17.0 # Apache-2.0 mock>=2.0.0 # BSD oslotest>=1.10.0 # Apache-2.0 coverage!=4.4,>=4.0 # Apache-2.0 testscenarios>=0.4 # Apache-2.0/BSD # for pre-release tests oslo.config>=5.1.0 # Apache-2.0 reno>=2.5.0 # Apache-2.0 oslo.i18n-3.19.0/oslo_i18n/0000775000175100017510000000000013211222152015164 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/log.py0000666000175100017510000000672613211221721016335 0ustar zuulzuul00000000000000# 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) oslo.i18n-3.19.0/oslo_i18n/_locale.py0000666000175100017510000000164713211221721017147 0ustar zuulzuul00000000000000# 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' oslo.i18n-3.19.0/oslo_i18n/__init__.py0000666000175100017510000000124113211221721017276 0ustar zuulzuul00000000000000# 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 * oslo.i18n-3.19.0/oslo_i18n/_factory.py0000666000175100017510000001571013211221721017353 0ustar zuulzuul00000000000000# 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') oslo.i18n-3.19.0/oslo_i18n/_i18n.py0000666000175100017510000000164613211221721016466 0ustar zuulzuul00000000000000# 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 oslo.i18n-3.19.0/oslo_i18n/_message.py0000666000175100017510000002263613211221721017335 0ustar zuulzuul00000000000000# 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) oslo.i18n-3.19.0/oslo_i18n/_translate.py0000666000175100017510000000546013211221721017702 0ustar zuulzuul00000000000000# 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 args.items()) return translated_dict return translate(args, desired_locale) oslo.i18n-3.19.0/oslo_i18n/locale/0000775000175100017510000000000013211222152016423 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/de/0000775000175100017510000000000013211222152017013 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/de/LC_MESSAGES/0000775000175100017510000000000013211222152020600 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/de/LC_MESSAGES/oslo_i18n.po0000666000175100017510000000163413211221721022762 0ustar zuulzuul00000000000000# 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." oslo.i18n-3.19.0/oslo_i18n/locale/zh_CN/0000775000175100017510000000000013211222152017424 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/zh_CN/LC_MESSAGES/0000775000175100017510000000000013211222152021211 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/zh_CN/LC_MESSAGES/oslo_i18n.po0000666000175100017510000000156513211221721023376 0ustar zuulzuul00000000000000# 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 "消息对象不支持添加操作。" oslo.i18n-3.19.0/oslo_i18n/locale/pl_PL/0000775000175100017510000000000013211222152017431 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/pl_PL/LC_MESSAGES/0000775000175100017510000000000013211222152021216 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/pl_PL/LC_MESSAGES/oslo_i18n.po0000666000175100017510000000170613211221721023400 0ustar zuulzuul00000000000000# 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." oslo.i18n-3.19.0/oslo_i18n/locale/fr/0000775000175100017510000000000013211222152017032 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/fr/LC_MESSAGES/0000775000175100017510000000000013211222152020617 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/fr/LC_MESSAGES/oslo_i18n.po0000666000175100017510000000171413211221721023000 0ustar zuulzuul00000000000000# 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." oslo.i18n-3.19.0/oslo_i18n/locale/en_GB/0000775000175100017510000000000013211222152017375 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/en_GB/LC_MESSAGES/0000775000175100017510000000000013211222152021162 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/en_GB/LC_MESSAGES/oslo_i18n.po0000666000175100017510000000161513211221721023343 0ustar zuulzuul00000000000000# 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." oslo.i18n-3.19.0/oslo_i18n/locale/ja/0000775000175100017510000000000013211222152017015 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/ja/LC_MESSAGES/0000775000175100017510000000000013211222152020602 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/ja/LC_MESSAGES/oslo_i18n.po0000666000175100017510000000127713211221721022767 0ustar zuulzuul00000000000000# 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 "メッセージオブジェクトは追加機能をサポートしていません。" oslo.i18n-3.19.0/oslo_i18n/locale/ko_KR/0000775000175100017510000000000013211222152017430 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/ko_KR/LC_MESSAGES/0000775000175100017510000000000013211222152021215 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/ko_KR/LC_MESSAGES/oslo_i18n.po0000666000175100017510000000162213211221721023374 0ustar zuulzuul00000000000000# 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 "메시지 객체는 추가 지원을하지 않습니다." oslo.i18n-3.19.0/oslo_i18n/locale/it/0000775000175100017510000000000013211222152017037 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/it/LC_MESSAGES/0000775000175100017510000000000013211222152020624 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/it/LC_MESSAGES/oslo_i18n.po0000666000175100017510000000162013211221721023001 0ustar zuulzuul00000000000000# 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." oslo.i18n-3.19.0/oslo_i18n/locale/pt/0000775000175100017510000000000013211222152017046 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/pt/LC_MESSAGES/0000775000175100017510000000000013211222152020633 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/pt/LC_MESSAGES/oslo_i18n.po0000666000175100017510000000161413211221721023013 0ustar zuulzuul00000000000000# 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." oslo.i18n-3.19.0/oslo_i18n/locale/es/0000775000175100017510000000000013211222152017032 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/es/LC_MESSAGES/0000775000175100017510000000000013211222152020617 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/locale/es/LC_MESSAGES/oslo_i18n.po0000666000175100017510000000163213211221721022777 0ustar zuulzuul00000000000000# 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." oslo.i18n-3.19.0/oslo_i18n/_lazy.py0000666000175100017510000000236213211221721016662 0ustar zuulzuul00000000000000# 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 oslo.i18n-3.19.0/oslo_i18n/fixture.py0000666000175100017510000001313313211221721017230 0ustar zuulzuul00000000000000# 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)) oslo.i18n-3.19.0/oslo_i18n/tests/0000775000175100017510000000000013211222152016326 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/tests/test_translate.py0000666000175100017510000000320413211221721021736 0ustar zuulzuul00000000000000# 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')) oslo.i18n-3.19.0/oslo_i18n/tests/test_public_api.py0000666000175100017510000000250513211221721022053 0ustar zuulzuul00000000000000# 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') oslo.i18n-3.19.0/oslo_i18n/tests/test_message.py0000666000175100017510000007063213211221721021376 0ustar zuulzuul00000000000000# 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(expected, result) self.assertEqual(expected, result.translate()) 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(expected, result) self.assertEqual(expected, result.translate()) 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(message, result.translate()) # simulate writing out as string result_str = '%s' % result.translate() self.assertEqual(result_str, message) self.assertEqual(message, result) 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('Found object: 1', result.translate()) 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("Found list: [1, 2, 3]", result.translate()) 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("Value: 5", result.translate()) 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("Values: 1 2", result.translate()) # Apply again to make sure other path works as well params = {'val1': 3, 'val2': utils.NoDeepCopyObject(4)} result = _message.Message(msgid) % params self.assertEqual("Values: 3 4", result.translate()) 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(expected, result) self.assertEqual(expected, result.translate()) # Make sure unused params still there self.assertEqual(params.keys(), result.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, ) oslo.i18n-3.19.0/oslo_i18n/tests/__init__.py0000666000175100017510000000000013211221721020430 0ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo_i18n/tests/test_fixture.py0000666000175100017510000001026413211221721021433 0ustar zuulzuul00000000000000# 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('this is a lazy message', msg.msgid) 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(u'this is a lazy message', msg) 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)) oslo.i18n-3.19.0/oslo_i18n/tests/test_handler.py0000666000175100017510000001035513211221721021363 0ustar zuulzuul00000000000000# 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()) oslo.i18n-3.19.0/oslo_i18n/tests/utils.py0000666000175100017510000000217313211221721020046 0ustar zuulzuul00000000000000# 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') oslo.i18n-3.19.0/oslo_i18n/tests/test_logging.py0000666000175100017510000000246613211221721021400 0ustar zuulzuul00000000000000# 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) oslo.i18n-3.19.0/oslo_i18n/tests/test_gettextutils.py0000666000175100017510000001263513211221721022516 0ustar zuulzuul00000000000000# 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) oslo.i18n-3.19.0/oslo_i18n/tests/test_factory.py0000666000175100017510000001377513211221721021426 0ustar zuulzuul00000000000000# 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) oslo.i18n-3.19.0/oslo_i18n/tests/test_lazy.py0000666000175100017510000000233213211221721020721 0ustar zuulzuul00000000000000# 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) oslo.i18n-3.19.0/oslo_i18n/tests/fakes.py0000666000175100017510000000373013211221721017777 0ustar zuulzuul00000000000000# 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 oslo.i18n-3.19.0/oslo_i18n/tests/test_locale_dir_variable.py0000666000175100017510000000231013211221721023700 0ustar zuulzuul00000000000000# 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) oslo.i18n-3.19.0/oslo_i18n/_gettextutils.py0000666000175100017510000000652413211221721020454 0ustar zuulzuul00000000000000# 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 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 aliases.items() if (locale in language_list and alias not in language_list)) language_list.extend(alias for locale, alias in aliases.items() if (locale not in language_list and find(alias))) # In webob.acceptparse, the best_match is just match the first element in # the language_list, so make the precise element in front result = ['en_US'] for i in language_list[1:]: if '_' in i: result.insert(1, i) else: result.append(i) _AVAILABLE_LANGUAGES[domain] = result return copy.copy(result) oslo.i18n-3.19.0/PKG-INFO0000664000175100017510000000400613211222152014446 0ustar zuulzuul00000000000000Metadata-Version: 1.1 Name: oslo.i18n Version: 3.19.0 Summary: Oslo i18n library Home-page: https://docs.openstack.org/oslo.i18n/latest Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: UNKNOWN Description-Content-Type: UNKNOWN Description: ======================== Team and repository tags ======================== .. image:: http://governance.openstack.org/badges/oslo.i18n.svg :target: http://governance.openstack.org/reference/tags/index.html .. Change things from this point on ================================================== 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: https://docs.openstack.org/oslo.i18n/latest * Source: https://git.openstack.org/cgit/openstack/oslo.i18n * Bugs: https://bugs.launchpad.net/oslo.i18n Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 oslo.i18n-3.19.0/oslo.i18n.egg-info/0000775000175100017510000000000013211222152016575 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/oslo.i18n.egg-info/top_level.txt0000664000175100017510000000001213211222151021317 0ustar zuulzuul00000000000000oslo_i18n oslo.i18n-3.19.0/oslo.i18n.egg-info/dependency_links.txt0000664000175100017510000000000113211222151022642 0ustar zuulzuul00000000000000 oslo.i18n-3.19.0/oslo.i18n.egg-info/PKG-INFO0000664000175100017510000000400613211222151017671 0ustar zuulzuul00000000000000Metadata-Version: 1.1 Name: oslo.i18n Version: 3.19.0 Summary: Oslo i18n library Home-page: https://docs.openstack.org/oslo.i18n/latest Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: UNKNOWN Description-Content-Type: UNKNOWN Description: ======================== Team and repository tags ======================== .. image:: http://governance.openstack.org/badges/oslo.i18n.svg :target: http://governance.openstack.org/reference/tags/index.html .. Change things from this point on ================================================== 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: https://docs.openstack.org/oslo.i18n/latest * Source: https://git.openstack.org/cgit/openstack/oslo.i18n * Bugs: https://bugs.launchpad.net/oslo.i18n Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 oslo.i18n-3.19.0/oslo.i18n.egg-info/SOURCES.txt0000664000175100017510000000421513211222152020463 0ustar zuulzuul00000000000000.coveragerc .mailmap .testr.conf AUTHORS CONTRIBUTING.rst ChangeLog HACKING.rst LICENSE README.rst babel.cfg requirements.txt setup.cfg setup.py test-requirements.txt tox.ini doc/source/conf.py doc/source/index.rst doc/source/contributor/contributing.rst doc/source/contributor/index.rst doc/source/contributor/policy.rst doc/source/reference/index.rst doc/source/user/guidelines.rst doc/source/user/history.rst doc/source/user/index.rst doc/source/user/usage.rst oslo.i18n.egg-info/PKG-INFO oslo.i18n.egg-info/SOURCES.txt oslo.i18n.egg-info/dependency_links.txt oslo.i18n.egg-info/not-zip-safe oslo.i18n.egg-info/pbr.json oslo.i18n.egg-info/requires.txt oslo.i18n.egg-info/top_level.txt oslo_i18n/__init__.py oslo_i18n/_factory.py oslo_i18n/_gettextutils.py oslo_i18n/_i18n.py oslo_i18n/_lazy.py oslo_i18n/_locale.py oslo_i18n/_message.py oslo_i18n/_translate.py oslo_i18n/fixture.py oslo_i18n/log.py oslo_i18n/locale/de/LC_MESSAGES/oslo_i18n.po oslo_i18n/locale/en_GB/LC_MESSAGES/oslo_i18n.po oslo_i18n/locale/es/LC_MESSAGES/oslo_i18n.po oslo_i18n/locale/fr/LC_MESSAGES/oslo_i18n.po oslo_i18n/locale/it/LC_MESSAGES/oslo_i18n.po oslo_i18n/locale/ja/LC_MESSAGES/oslo_i18n.po oslo_i18n/locale/ko_KR/LC_MESSAGES/oslo_i18n.po oslo_i18n/locale/pl_PL/LC_MESSAGES/oslo_i18n.po oslo_i18n/locale/pt/LC_MESSAGES/oslo_i18n.po oslo_i18n/locale/zh_CN/LC_MESSAGES/oslo_i18n.po oslo_i18n/tests/__init__.py oslo_i18n/tests/fakes.py oslo_i18n/tests/test_factory.py oslo_i18n/tests/test_fixture.py oslo_i18n/tests/test_gettextutils.py oslo_i18n/tests/test_handler.py oslo_i18n/tests/test_lazy.py oslo_i18n/tests/test_locale_dir_variable.py oslo_i18n/tests/test_logging.py oslo_i18n/tests/test_message.py oslo_i18n/tests/test_public_api.py oslo_i18n/tests/test_translate.py oslo_i18n/tests/utils.py releasenotes/notes/add-reno-996dd44974d53238.yaml releasenotes/source/conf.py releasenotes/source/index.rst releasenotes/source/ocata.rst releasenotes/source/pike.rst releasenotes/source/unreleased.rst releasenotes/source/_static/.placeholder releasenotes/source/_templates/.placeholder releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.pooslo.i18n-3.19.0/oslo.i18n.egg-info/requires.txt0000664000175100017510000000006413211222151021174 0ustar zuulzuul00000000000000pbr!=2.1.0,>=2.0.0 Babel!=2.4.0,>=2.3.4 six>=1.10.0 oslo.i18n-3.19.0/oslo.i18n.egg-info/not-zip-safe0000664000175100017510000000000113211222115021022 0ustar zuulzuul00000000000000 oslo.i18n-3.19.0/oslo.i18n.egg-info/pbr.json0000664000175100017510000000005613211222151020253 0ustar zuulzuul00000000000000{"git_version": "79e468e", "is_release": true}oslo.i18n-3.19.0/releasenotes/0000775000175100017510000000000013211222152016042 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/releasenotes/notes/0000775000175100017510000000000013211222152017172 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/releasenotes/notes/add-reno-996dd44974d53238.yaml0000666000175100017510000000007213211221721023573 0ustar zuulzuul00000000000000--- other: - Introduce reno for deployer release notes. oslo.i18n-3.19.0/releasenotes/source/0000775000175100017510000000000013211222152017342 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/releasenotes/source/conf.py0000666000175100017510000002146713211221721020656 0ustar zuulzuul00000000000000# -*- 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. # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'openstackdocstheme', 'reno.sphinxext', ] # openstackdocstheme options repository_name = 'openstack/oslo.i18n' bug_project = 'oslo.i18n' bug_tag = '' html_last_updated_fmt = '%Y-%m-%d %H:%M' # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'oslo.i18n Release Notes' copyright = u'2016, oslo.i18n Developers' # Release notes do not need a version in the title, they span # multiple versions. # The full version, including alpha/beta/rc tags. release = '' # The short X.Y version. version = '' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all # documents. # default_role = None # 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 # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. # keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'openstackdocs' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". # html_title = None # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. # html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. # html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = {} # If false, no module index is generated. # html_domain_indices = True # If false, no index is generated. # html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'oslo.i18nReleaseNotesDoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # 'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'oslo.i18nReleaseNotes.tex', u'oslo.i18n Release Notes Documentation', u'oslo.i18n Developers', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # If true, show page references after internal links. # latex_show_pagerefs = False # If true, show URL addresses after external links. # latex_show_urls = False # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'oslo.i18nReleaseNotes', u'oslo.i18n Release Notes Documentation', [u'oslo.i18n Developers'], 1) ] # If true, show URL addresses after external links. # man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'oslo.i18nReleaseNotes', u'oslo.i18n Release Notes Documentation', u'oslo.i18n Developers', 'oslo.i18nReleaseNotes', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. # texinfo_appendices = [] # If false, no module index is generated. # texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. # texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. # texinfo_no_detailmenu = False # -- Options for Internationalization output ------------------------------ locale_dirs = ['locale/'] oslo.i18n-3.19.0/releasenotes/source/_static/0000775000175100017510000000000013211222152020770 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/releasenotes/source/_static/.placeholder0000666000175100017510000000000013211221721023244 0ustar zuulzuul00000000000000oslo.i18n-3.19.0/releasenotes/source/index.rst0000666000175100017510000000022013211221721021200 0ustar zuulzuul00000000000000========================= oslo.i18n Release Notes ========================= .. toctree:: :maxdepth: 1 unreleased pike ocata oslo.i18n-3.19.0/releasenotes/source/_templates/0000775000175100017510000000000013211222152021477 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/releasenotes/source/_templates/.placeholder0000666000175100017510000000000013211221721023753 0ustar zuulzuul00000000000000oslo.i18n-3.19.0/releasenotes/source/ocata.rst0000666000175100017510000000023013211221721021161 0ustar zuulzuul00000000000000=================================== Ocata Series Release Notes =================================== .. release-notes:: :branch: origin/stable/ocata oslo.i18n-3.19.0/releasenotes/source/pike.rst0000666000175100017510000000021713211221721021027 0ustar zuulzuul00000000000000=================================== Pike Series Release Notes =================================== .. release-notes:: :branch: stable/pike oslo.i18n-3.19.0/releasenotes/source/locale/0000775000175100017510000000000013211222152020601 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/releasenotes/source/locale/en_GB/0000775000175100017510000000000013211222152021553 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/releasenotes/source/locale/en_GB/LC_MESSAGES/0000775000175100017510000000000013211222152023340 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/releasenotes/source/locale/en_GB/LC_MESSAGES/releasenotes.po0000666000175100017510000000174313211221721026401 0ustar zuulzuul00000000000000# Andi Chandler , 2017. #zanata msgid "" msgstr "" "Project-Id-Version: oslo.i18n Release Notes 3.18.1.dev1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-09-20 20:47+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2017-10-05 03:55+0000\n" "Last-Translator: Andi Chandler \n" "Language-Team: English (United Kingdom)\n" "Language: en-GB\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" msgid "3.11.0" msgstr "3.11.0" msgid "Introduce reno for deployer release notes." msgstr "Introduce reno for deployer release notes." msgid "Ocata Series Release Notes" msgstr "Ocata Series Release Notes" msgid "Other Notes" msgstr "Other Notes" msgid "Pike Series Release Notes" msgstr "Pike Series Release Notes" msgid "Unreleased Release Notes" msgstr "Unreleased Release Notes" msgid "oslo.i18n Release Notes" msgstr "oslo.i18n Release Notes" oslo.i18n-3.19.0/releasenotes/source/locale/ko_KR/0000775000175100017510000000000013211222152021606 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/releasenotes/source/locale/ko_KR/LC_MESSAGES/0000775000175100017510000000000013211222152023373 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/releasenotes/source/locale/ko_KR/LC_MESSAGES/releasenotes.po0000666000175100017510000000203113211221721026423 0ustar zuulzuul00000000000000# minwook-shin , 2017. #zanata msgid "" msgstr "" "Project-Id-Version: oslo.i18n Release Notes 3.17.1.dev2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-07-29 12:23+0000\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2017-08-04 07:11+0000\n" "Last-Translator: minwook-shin \n" "Language-Team: Korean (South Korea)\n" "Language: ko-KR\n" "X-Generator: Zanata 3.9.6\n" "Plural-Forms: nplurals=1; plural=0\n" msgid "3.11.0" msgstr "3.11.0" msgid "Introduce reno for deployer release notes." msgstr "릴리즈 노트 배포에 reno를 도입하기." msgid "Ocata Series Release Notes" msgstr "Ocata 시리즈에 대한 릴리즈 노트" msgid "Other Notes" msgstr "기타 노트" msgid "Pike Series Release Notes" msgstr "Pike 시리즈에 대한 릴리즈 노트" msgid "Unreleased Release Notes" msgstr "릴리즈되지않은 릴리즈 노트" msgid "oslo.i18n Release Notes" msgstr "oslo.i18n 릴리즈 노트" oslo.i18n-3.19.0/releasenotes/source/unreleased.rst0000666000175100017510000000014413211221721022225 0ustar zuulzuul00000000000000========================== Unreleased Release Notes ========================== .. release-notes:: oslo.i18n-3.19.0/HACKING.rst0000666000175100017510000000017013211221721015150 0ustar zuulzuul00000000000000Style Commandments ================== Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/ oslo.i18n-3.19.0/requirements.txt0000666000175100017510000000044013211221721016636 0ustar zuulzuul00000000000000# 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!=2.1.0,>=2.0.0 # Apache-2.0 Babel!=2.4.0,>=2.3.4 # BSD six>=1.10.0 # MIT oslo.i18n-3.19.0/setup.py0000666000175100017510000000200613211221721015064 0ustar zuulzuul00000000000000# 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>=2.0.0'], pbr=True) oslo.i18n-3.19.0/README.rst0000666000175100017510000000200713211221721015042 0ustar zuulzuul00000000000000======================== Team and repository tags ======================== .. image:: http://governance.openstack.org/badges/oslo.i18n.svg :target: http://governance.openstack.org/reference/tags/index.html .. Change things from this point on ================================================== 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: https://docs.openstack.org/oslo.i18n/latest * Source: https://git.openstack.org/cgit/openstack/oslo.i18n * Bugs: https://bugs.launchpad.net/oslo.i18n oslo.i18n-3.19.0/doc/0000775000175100017510000000000013211222152014116 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/doc/source/0000775000175100017510000000000013211222152015416 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/doc/source/conf.py0000777000175100017510000000515613211221721016732 0ustar zuulzuul00000000000000# -*- 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', 'openstackdocstheme' ] # openstackdocstheme options repository_name = 'openstack/oslo.i18n' bug_project = 'oslo.i18n' bug_tag = '' html_last_updated_fmt = '%Y-%m-%d %H:%M' # 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_theme = 'openstackdocs' 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} oslo.i18n-3.19.0/doc/source/contributor/0000775000175100017510000000000013211222152017770 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/doc/source/contributor/index.rst0000666000175100017510000000021413211221721021631 0ustar zuulzuul00000000000000=========================== Contributing to oslo.i18n =========================== .. toctree:: :maxdepth: 2 contributing policy oslo.i18n-3.19.0/doc/source/contributor/contributing.rst0000666000175100017510000000012413211221721023231 0ustar zuulzuul00000000000000============== Contributing ============== .. include:: ../../../CONTRIBUTING.rst oslo.i18n-3.19.0/doc/source/contributor/policy.rst0000666000175100017510000000075313211221721022031 0ustar zuulzuul00000000000000================ Policy History ================ * `Discussion from Havana Summit `__ * `Discussion from Icehouse Summit `__ * `Discussion from Juno Summit `__ * `I18n team wiki page `__ * `LoggingStandards wiki page `__ oslo.i18n-3.19.0/doc/source/index.rst0000666000175100017510000000072613211221721017267 0ustar zuulzuul00000000000000================================================== 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. .. toctree:: :maxdepth: 2 user/index reference/index contributor/index .. rubric:: Indices and tables * :ref:`modindex` * :ref:`search` oslo.i18n-3.19.0/doc/source/user/0000775000175100017510000000000013211222152016374 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/doc/source/user/index.rst0000666000175100017510000000016713211221721020244 0ustar zuulzuul00000000000000================= Using oslo.i18n ================= .. toctree:: :maxdepth: 2 usage guidelines history oslo.i18n-3.19.0/doc/source/user/usage.rst0000666000175100017510000002013513211221721020236 0ustar zuulzuul00000000000000.. _usage: ===================================================== 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. .. note:: Starting with the Pike series, OpenStack no longer supports log translation. It is not necessary to add translation instructions to new code, and the instructions can be removed from old code. Refer to the email thread `understanding log domain change `_ on the openstack-dev mailing list for more details. .. 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. # # NOTE(dhellmann): This is not needed for new projects as of the # Pike series. # # 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` Displaying translated messages ============================== Several preparations are required to display translated messages in your running application. Preferred language You need to specify your preferred language through an environment variable. The preferred language can be specified by ``LANGUAGE``, ``LC_ALL``, ``LC_MESSAGES``, or ``LANGUAGE`` (A former one has a priority). ``oslo_i18n.translate()`` can be used to translate a string to override the preferred language. .. note:: You need to use ``enable_lazy()`` to override the preferred language by using ``oslo_i18n.translate()``. Locale directory Python ``gettext`` looks for binary ``mo`` files for the given domain using the path ``//LC_MESSAGES/.mo``. The default locale directory varies on distributions, and it is ``/usr/share/locale`` in most cases. If you store message catalogs in a different location, you need to specify the location via an environment variable named ``_LOCALEDIR`` where ```` is an upper-case domain name with replacing ``_`` and ``.`` with ``-``. For example, ``NEUTRON_LOCALEDIR`` for a domain ``neutron`` and ``OSLO_I18N_LOCALEDIR`` for a domain ``oslo_i18n``. .. note:: When you specify locale directories via ``_LOCALEDIR`` environment variables, you need to specify an environment variable per domain. More concretely, if your application using a domain ``myapp` uses oslo.policy, you need to specify both ``MYAPP_LOCALEDIR`` and ``OSLO_POLICY_LOCALEDIR`` to ensure that translation messages from both your application and oslo.policy are displayed. oslo.i18n-3.19.0/doc/source/user/guidelines.rst0000666000175100017510000001742613211221721021273 0ustar zuulzuul00000000000000================================= 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:: * :ref:`usage` * :ref:`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 =============== .. note:: Starting with the Pike series, OpenStack no longer supports log translation. It is not necessary to add translation instructions to new code, and the instructions can be removed from old code. Refer to the email thread `understanding log domain change `_ on the openstack-dev mailing list for more details. 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 occurred.')) Instead, use this style:: # RIGHT LOG.exception(_LE('There was an error.')) raise LocalExceptionClass(_('An error occurred.')) 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. oslo.i18n-3.19.0/doc/source/user/history.rst0000666000175100017510000000004013211221721020624 0ustar zuulzuul00000000000000.. include:: ../../../ChangeLog oslo.i18n-3.19.0/doc/source/reference/0000775000175100017510000000000013211222152017354 5ustar zuulzuul00000000000000oslo.i18n-3.19.0/doc/source/reference/index.rst0000666000175100017510000000116413211221721021222 0ustar zuulzuul00000000000000.. _api: =============== oslo.i18n 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: oslo.i18n-3.19.0/CONTRIBUTING.rst0000666000175100017510000000103313211221721016012 0ustar zuulzuul00000000000000If 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.i18noslo.i18n-3.19.0/.testr.conf0000666000175100017510000000047613211221721015451 0ustar zuulzuul00000000000000[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=--listoslo.i18n-3.19.0/babel.cfg0000666000175100017510000000002013211221721015072 0ustar zuulzuul00000000000000[python: **.py] oslo.i18n-3.19.0/.coveragerc0000666000175100017510000000015513211221721015476 0ustar zuulzuul00000000000000[run] branch = True source = oslo_i18n omit = oslo_i18n/tests/* [report] ignore_errors = True precision = 2