2011-04-19 05:02:57 +08:00
# -*- encoding: utf-8 -*-
2012-12-08 18:13:52 +08:00
from __future__ import unicode_literals
2011-12-11 08:48:26 +08:00
2013-10-21 11:22:32 +08:00
import io
2010-02-22 07:45:04 +08:00
import os
import re
import shutil
2014-03-24 21:03:06 +08:00
import time
2013-10-28 21:17:48 +08:00
from unittest import SkipTest , skipUnless
2013-01-21 02:07:10 +08:00
import warnings
2011-10-14 05:34:56 +08:00
2013-11-30 17:53:08 +08:00
from django . conf import settings
2010-02-22 07:45:04 +08:00
from django . core import management
2014-05-01 15:03:24 +08:00
from django . core . management import execute_from_command_line
2013-10-28 21:17:48 +08:00
from django . core . management . utils import find_command
2013-01-17 11:35:46 +08:00
from django . test import SimpleTestCase
2013-12-23 23:01:13 +08:00
from django . test import override_settings
2014-11-29 06:47:53 +08:00
from django . test . utils import captured_stderr , captured_stdout
2012-12-08 18:13:52 +08:00
from django . utils . encoding import force_text
from django . utils . _os import upath
2013-01-26 20:47:11 +08:00
from django . utils import six
2012-08-07 21:41:54 +08:00
from django . utils . six import StringIO
2013-01-21 02:07:10 +08:00
from django . utils . translation import TranslatorCommentWarning
2011-10-14 05:34:56 +08:00
2010-02-22 07:45:04 +08:00
2013-10-23 18:09:29 +08:00
LOCALE = ' de '
2013-10-28 21:17:48 +08:00
has_xgettext = find_command ( ' xgettext ' )
2014-07-15 17:10:50 +08:00
this_directory = os . path . dirname ( upath ( __file__ ) )
2010-02-22 07:45:04 +08:00
2013-11-03 12:36:09 +08:00
2013-10-28 21:17:48 +08:00
@skipUnless ( has_xgettext , ' xgettext is mandatory for extraction tests ' )
2013-01-17 11:35:46 +08:00
class ExtractorTests ( SimpleTestCase ) :
2010-02-22 07:45:04 +08:00
2014-07-15 17:10:50 +08:00
test_dir = os . path . abspath ( os . path . join ( this_directory , ' commands ' ) )
2014-03-24 21:03:06 +08:00
2013-10-23 18:09:29 +08:00
PO_FILE = ' locale/ %s /LC_MESSAGES/django.po ' % LOCALE
2010-02-22 07:45:04 +08:00
def setUp ( self ) :
self . _cwd = os . getcwd ( )
def _rmrf ( self , dname ) :
if os . path . commonprefix ( [ self . test_dir , os . path . abspath ( dname ) ] ) != self . test_dir :
return
shutil . rmtree ( dname )
2013-05-06 11:32:07 +08:00
def rmfile ( self , filepath ) :
if os . path . exists ( filepath ) :
os . remove ( filepath )
2010-02-22 07:45:04 +08:00
def tearDown ( self ) :
os . chdir ( self . test_dir )
try :
self . _rmrf ( ' locale/ %s ' % LOCALE )
except OSError :
pass
os . chdir ( self . _cwd )
2014-10-18 18:00:38 +08:00
def _run_makemessages ( self , * * options ) :
os . chdir ( self . test_dir )
2014-10-22 01:15:10 +08:00
out = StringIO ( )
2014-10-18 18:00:38 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 2 ,
2014-10-22 01:15:10 +08:00
stdout = out , * * options )
output = out . getvalue ( )
2014-10-18 18:00:38 +08:00
self . assertTrue ( os . path . exists ( self . PO_FILE ) )
with open ( self . PO_FILE , ' r ' ) as fp :
po_contents = fp . read ( )
return output , po_contents
2010-11-04 20:08:37 +08:00
def assertMsgId ( self , msgid , s , use_quotes = True ) :
2011-12-11 08:07:06 +08:00
q = ' " '
2010-11-04 20:08:37 +08:00
if use_quotes :
msgid = ' " %s " ' % msgid
2011-12-11 08:07:06 +08:00
q = " ' "
needle = ' msgid %s ' % msgid
2011-06-08 00:11:25 +08:00
msgid = re . escape ( msgid )
2013-10-27 03:15:03 +08:00
return self . assertTrue ( re . search ( ' ^msgid %s ' % msgid , s , re . MULTILINE ) , ' Could not find %(q)s %(n)s %(q)s in generated PO file ' % { ' n ' : needle , ' q ' : q } )
2010-02-22 07:45:04 +08:00
2010-11-04 20:08:37 +08:00
def assertNotMsgId ( self , msgid , s , use_quotes = True ) :
if use_quotes :
msgid = ' " %s " ' % msgid
2011-06-08 00:11:25 +08:00
msgid = re . escape ( msgid )
2011-03-03 23:04:39 +08:00
return self . assertTrue ( not re . search ( ' ^msgid %s ' % msgid , s , re . MULTILINE ) )
2010-02-22 07:45:04 +08:00
2013-11-08 22:44:37 +08:00
def _assertPoLocComment ( self , assert_presence , po_filename , line_number , * comment_parts ) :
with open ( po_filename , ' r ' ) as fp :
po_contents = force_text ( fp . read ( ) )
if os . name == ' nt ' :
# #: .\path\to\file.html:123
cwd_prefix = ' %s %s ' % ( os . curdir , os . sep )
else :
# #: path/to/file.html:123
cwd_prefix = ' '
parts = [ ' #: ' ]
parts . append ( os . path . join ( cwd_prefix , * comment_parts ) )
if line_number is not None :
parts . append ( ' : %d ' % line_number )
needle = ' ' . join ( parts )
if assert_presence :
2014-10-28 18:02:56 +08:00
return self . assertIn ( needle , po_contents , ' " %s " not found in final .po file. ' % needle )
2013-11-08 22:44:37 +08:00
else :
2014-10-28 18:02:56 +08:00
return self . assertNotIn ( needle , po_contents , ' " %s " shouldn \' t be in final .po file. ' % needle )
2013-11-08 22:44:37 +08:00
def assertLocationCommentPresent ( self , po_filename , line_number , * comment_parts ) :
"""
self . assertLocationCommentPresent ( ' django.po ' , 42 , ' dirA ' , ' dirB ' , ' foo.py ' )
verifies that the django . po file has a gettext - style location comment of the form
` #: dirA/dirB/foo.py:42`
( or ` #: .\dirA\dirB\foo.py:42` on Windows)
None can be passed for the line_number argument to skip checking of the : 42 suffix part .
"""
return self . _assertPoLocComment ( True , po_filename , line_number , * comment_parts )
def assertLocationCommentNotPresent ( self , po_filename , line_number , * comment_parts ) :
2014-03-02 22:25:53 +08:00
""" Check the opposite of assertLocationComment() """
2013-11-08 22:44:37 +08:00
return self . _assertPoLocComment ( False , po_filename , line_number , * comment_parts )
2014-03-24 21:03:06 +08:00
def assertRecentlyModified ( self , path ) :
"""
Assert that file was recently modified ( modification time was less than 10 seconds ago ) .
"""
delta = time . time ( ) - os . stat ( path ) . st_mtime
self . assertLess ( delta , 10 , " %s was recently modified " % path )
def assertNotRecentlyModified ( self , path ) :
"""
Assert that file was not recently modified ( modification time was more than 10 seconds ago ) .
"""
delta = time . time ( ) - os . stat ( path ) . st_mtime
self . assertGreater ( delta , 10 , " %s wasn ' t recently modified " % path )
2010-02-22 07:45:04 +08:00
2010-11-17 23:37:33 +08:00
class BasicExtractorTests ( ExtractorTests ) :
def test_comments_extractor ( self ) :
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 )
2011-03-03 23:04:39 +08:00
self . assertTrue ( os . path . exists ( self . PO_FILE ) )
2013-10-21 11:22:32 +08:00
with io . open ( self . PO_FILE , ' r ' , encoding = ' utf-8 ' ) as fp :
po_contents = fp . read ( )
2014-10-28 18:02:56 +08:00
self . assertIn ( ' #. Translators: This comment should be extracted ' , po_contents )
self . assertNotIn ( ' This comment should not be extracted ' , po_contents )
2011-12-11 08:07:06 +08:00
# Comments in templates
2014-10-28 18:02:56 +08:00
self . assertIn ( ' #. Translators: Django template comment for translators ' , po_contents )
self . assertIn ( " #. Translators: Django comment block for translators \n #. string ' s meaning unveiled " , po_contents )
2011-03-19 20:56:38 +08:00
2014-10-28 18:02:56 +08:00
self . assertIn ( ' #. Translators: One-line translator comment #1 ' , po_contents )
self . assertIn ( ' #. Translators: Two-line translator comment #1 \n #. continued here. ' , po_contents )
2011-03-19 20:56:38 +08:00
2014-10-28 18:02:56 +08:00
self . assertIn ( ' #. Translators: One-line translator comment #2 ' , po_contents )
self . assertIn ( ' #. Translators: Two-line translator comment #2 \n #. continued here. ' , po_contents )
2011-03-19 20:56:38 +08:00
2014-10-28 18:02:56 +08:00
self . assertIn ( ' #. Translators: One-line translator comment #3 ' , po_contents )
self . assertIn ( ' #. Translators: Two-line translator comment #3 \n #. continued here. ' , po_contents )
2011-03-19 20:56:38 +08:00
2014-10-28 18:02:56 +08:00
self . assertIn ( ' #. Translators: One-line translator comment #4 ' , po_contents )
self . assertIn ( ' #. Translators: Two-line translator comment #4 \n #. continued here. ' , po_contents )
2010-11-04 22:06:24 +08:00
2014-10-28 18:02:56 +08:00
self . assertIn ( ' #. Translators: One-line translator comment #5 -- with non ASCII characters: áéíóúö ' , po_contents )
self . assertIn ( ' #. Translators: Two-line translator comment #5 -- with non ASCII characters: áéíóúö \n #. continued here. ' , po_contents )
2011-04-19 05:02:57 +08:00
2011-12-11 08:07:06 +08:00
def test_templatize_trans_tag ( self ) :
# ticket #11240
2010-11-04 22:06:24 +08:00
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 )
2011-03-03 23:04:39 +08:00
self . assertTrue ( os . path . exists ( self . PO_FILE ) )
2011-12-11 08:07:06 +08:00
with open ( self . PO_FILE , ' r ' ) as fp :
2012-12-08 18:13:52 +08:00
po_contents = force_text ( fp . read ( ) )
2011-12-11 08:07:06 +08:00
self . assertMsgId ( ' Literal with a percent symbol at the end %% ' , po_contents )
self . assertMsgId ( ' Literal with a percent %% symbol in the middle ' , po_contents )
self . assertMsgId ( ' Completed 50 %% of all the tasks ' , po_contents )
self . assertMsgId ( ' Completed 99 %% of all the tasks ' , po_contents )
self . assertMsgId ( " Shouldn ' t double escape this sequence: %% (two percent signs) " , po_contents )
self . assertMsgId ( " Shouldn ' t double escape this sequence %% either " , po_contents )
self . assertMsgId ( " Looks like a str fmt spec %% s but shouldn ' t be interpreted as such " , po_contents )
self . assertMsgId ( " Looks like a str fmt spec %% o but shouldn ' t be interpreted as such " , po_contents )
def test_templatize_blocktrans_tag ( self ) :
# ticket #11966
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 )
2011-12-11 08:07:06 +08:00
self . assertTrue ( os . path . exists ( self . PO_FILE ) )
with open ( self . PO_FILE , ' r ' ) as fp :
2012-12-08 18:13:52 +08:00
po_contents = force_text ( fp . read ( ) )
2011-12-11 08:07:06 +08:00
self . assertMsgId ( ' I think that 100 %% is more that 50 %% of anything. ' , po_contents )
self . assertMsgId ( ' I think that 100 %% is more that 50 %% of %(obj)s . ' , po_contents )
2011-12-11 08:48:26 +08:00
self . assertMsgId ( " Blocktrans extraction shouldn ' t double escape this: %% , a= %(a)s " , po_contents )
2010-11-04 22:06:24 +08:00
2013-11-03 03:01:17 +08:00
def test_blocktrans_trimmed ( self ) :
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 )
2013-11-03 03:01:17 +08:00
self . assertTrue ( os . path . exists ( self . PO_FILE ) )
with open ( self . PO_FILE , ' r ' ) as fp :
po_contents = force_text ( fp . read ( ) )
# should not be trimmed
self . assertNotMsgId ( ' Text with a few line breaks. ' , po_contents )
# should be trimmed
self . assertMsgId ( " Again some text with a few line breaks, this time should be trimmed. " , po_contents )
2013-11-08 22:44:37 +08:00
# #21406 -- Should adjust for eaten line numbers
self . assertMsgId ( " I ' m on line 97 " , po_contents )
self . assertLocationCommentPresent ( self . PO_FILE , 97 , ' templates ' , ' test.html ' )
2013-11-03 03:01:17 +08:00
2013-02-04 07:53:48 +08:00
def test_force_en_us_locale ( self ) :
""" Value of locale-munging option used by the command is the right one """
from django . core . management . commands . makemessages import Command
self . assertTrue ( Command . leave_locale_alone )
2010-12-05 01:42:54 +08:00
def test_extraction_error ( self ) :
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
self . assertRaises ( SyntaxError , management . call_command , ' makemessages ' , locale = [ LOCALE ] , extensions = [ ' tpl ' ] , verbosity = 0 )
2011-12-21 23:35:58 +08:00
with self . assertRaises ( SyntaxError ) as context_manager :
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , extensions = [ ' tpl ' ] , verbosity = 0 )
2013-11-03 12:36:09 +08:00
six . assertRegex (
self , str ( context_manager . exception ) ,
r ' Translation blocks must not include other block tags: blocktrans \ (file templates[/ \\ ]template_with_error \ .tpl, line 3 \ ) '
)
2011-12-21 23:35:58 +08:00
# Check that the temporary file was cleaned up
2013-01-24 18:51:14 +08:00
self . assertFalse ( os . path . exists ( ' ./templates/template_with_error.tpl.py ' ) )
2010-12-05 01:42:54 +08:00
2013-05-06 11:32:07 +08:00
def test_unicode_decode_error ( self ) :
os . chdir ( self . test_dir )
shutil . copyfile ( ' ./not_utf8.sample ' , ' ./not_utf8.txt ' )
self . addCleanup ( self . rmfile , os . path . join ( self . test_dir , ' not_utf8.txt ' ) )
2014-10-22 01:15:10 +08:00
out = StringIO ( )
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , stdout = out )
2013-05-06 11:32:07 +08:00
self . assertIn ( " UnicodeDecodeError: skipped file not_utf8.txt in . " ,
2014-10-22 01:15:10 +08:00
force_text ( out . getvalue ( ) ) )
2013-05-06 11:32:07 +08:00
2012-07-19 00:34:13 +08:00
def test_extraction_warning ( self ) :
2013-01-21 02:07:10 +08:00
""" test xgettext warning about multiple bare interpolation placeholders """
2012-07-19 00:34:13 +08:00
os . chdir ( self . test_dir )
shutil . copyfile ( ' ./code.sample ' , ' ./code_sample.py ' )
2013-05-06 11:32:07 +08:00
self . addCleanup ( self . rmfile , os . path . join ( self . test_dir , ' code_sample.py ' ) )
2014-10-22 01:15:10 +08:00
out = StringIO ( )
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , stdout = out )
self . assertIn ( " code_sample.py:4 " , force_text ( out . getvalue ( ) ) )
2012-07-19 00:34:13 +08:00
2011-10-19 12:59:47 +08:00
def test_template_message_context_extractor ( self ) :
"""
Ensure that message contexts are correctly extracted for the
{ % trans % } and { % blocktrans % } template tags .
Refs #14806.
"""
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 )
2011-10-19 12:59:47 +08:00
self . assertTrue ( os . path . exists ( self . PO_FILE ) )
2011-12-11 08:07:06 +08:00
with open ( self . PO_FILE , ' r ' ) as fp :
2012-12-08 18:13:52 +08:00
po_contents = force_text ( fp . read ( ) )
2011-12-11 08:07:06 +08:00
# {% trans %}
2014-10-28 18:02:56 +08:00
self . assertIn ( ' msgctxt " Special trans context #1 " ' , po_contents )
2013-01-24 18:51:14 +08:00
self . assertMsgId ( " Translatable literal #7a " , po_contents )
2014-10-28 18:02:56 +08:00
self . assertIn ( ' msgctxt " Special trans context #2 " ' , po_contents )
2013-01-24 18:51:14 +08:00
self . assertMsgId ( " Translatable literal #7b " , po_contents )
2014-10-28 18:02:56 +08:00
self . assertIn ( ' msgctxt " Special trans context #3 " ' , po_contents )
2013-01-24 18:51:14 +08:00
self . assertMsgId ( " Translatable literal #7c " , po_contents )
2011-12-11 08:07:06 +08:00
# {% blocktrans %}
2014-10-28 18:02:56 +08:00
self . assertIn ( ' msgctxt " Special blocktrans context #1 " ' , po_contents )
2013-01-24 18:51:14 +08:00
self . assertMsgId ( " Translatable literal #8a " , po_contents )
2014-10-28 18:02:56 +08:00
self . assertIn ( ' msgctxt " Special blocktrans context #2 " ' , po_contents )
2013-01-24 18:51:14 +08:00
self . assertMsgId ( " Translatable literal #8b-singular " , po_contents )
2014-10-28 18:02:56 +08:00
self . assertIn ( " Translatable literal #8b-plural " , po_contents )
self . assertIn ( ' msgctxt " Special blocktrans context #3 " ' , po_contents )
2013-01-24 18:51:14 +08:00
self . assertMsgId ( " Translatable literal #8c-singular " , po_contents )
2014-10-28 18:02:56 +08:00
self . assertIn ( " Translatable literal #8c-plural " , po_contents )
self . assertIn ( ' msgctxt " Special blocktrans context #4 " ' , po_contents )
2013-01-24 18:51:14 +08:00
self . assertMsgId ( " Translatable literal #8d %(a)s " , po_contents )
2010-11-04 22:06:24 +08:00
2012-09-28 11:34:45 +08:00
def test_context_in_single_quotes ( self ) :
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 )
2012-09-28 11:34:45 +08:00
self . assertTrue ( os . path . exists ( self . PO_FILE ) )
with open ( self . PO_FILE , ' r ' ) as fp :
2012-12-08 18:13:52 +08:00
po_contents = force_text ( fp . read ( ) )
2012-09-28 11:34:45 +08:00
# {% trans %}
2014-10-28 18:02:56 +08:00
self . assertIn ( ' msgctxt " Context wrapped in double quotes " ' , po_contents )
self . assertIn ( ' msgctxt " Context wrapped in single quotes " ' , po_contents )
2012-09-28 11:34:45 +08:00
# {% blocktrans %}
2014-10-28 18:02:56 +08:00
self . assertIn ( ' msgctxt " Special blocktrans context wrapped in double quotes " ' , po_contents )
self . assertIn ( ' msgctxt " Special blocktrans context wrapped in single quotes " ' , po_contents )
2012-09-28 11:34:45 +08:00
2013-01-21 02:07:10 +08:00
def test_template_comments ( self ) :
""" Template comment tags on the same line of other constructs (#19552) """
os . chdir ( self . test_dir )
# Test detection/end user reporting of old, incorrect templates
# translator comments syntax
with warnings . catch_warnings ( record = True ) as ws :
warnings . simplefilter ( ' always ' )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , extensions = [ ' thtml ' ] , verbosity = 0 )
2013-01-21 02:07:10 +08:00
self . assertEqual ( len ( ws ) , 3 )
for w in ws :
self . assertTrue ( issubclass ( w . category , TranslatorCommentWarning ) )
2013-11-03 12:36:09 +08:00
six . assertRegex (
self , str ( ws [ 0 ] . message ) ,
2013-10-02 10:59:19 +08:00
r " The translator-targeted comment ' Translators: ignored i18n comment #1 ' \ (file templates[/ \\ ]comments.thtml, line 4 \ ) was ignored, because it wasn ' t the last item on the line \ . "
2013-01-21 02:07:10 +08:00
)
2013-11-03 12:36:09 +08:00
six . assertRegex (
self , str ( ws [ 1 ] . message ) ,
2013-10-02 10:59:19 +08:00
r " The translator-targeted comment ' Translators: ignored i18n comment #3 ' \ (file templates[/ \\ ]comments.thtml, line 6 \ ) was ignored, because it wasn ' t the last item on the line \ . "
2013-01-21 02:07:10 +08:00
)
2013-11-03 12:36:09 +08:00
six . assertRegex (
self , str ( ws [ 2 ] . message ) ,
2013-10-02 10:59:19 +08:00
r " The translator-targeted comment ' Translators: ignored i18n comment #4 ' \ (file templates[/ \\ ]comments.thtml, line 8 \ ) was ignored, because it wasn ' t the last item on the line \ . "
2013-01-21 02:07:10 +08:00
)
# Now test .po file contents
self . assertTrue ( os . path . exists ( self . PO_FILE ) )
with open ( self . PO_FILE , ' r ' ) as fp :
po_contents = force_text ( fp . read ( ) )
self . assertMsgId ( ' Translatable literal #9a ' , po_contents )
2014-10-28 18:02:56 +08:00
self . assertNotIn ( ' ignored comment #1 ' , po_contents )
2013-01-21 02:07:10 +08:00
2014-10-28 18:02:56 +08:00
self . assertNotIn ( ' Translators: ignored i18n comment #1 ' , po_contents )
2013-01-21 02:07:10 +08:00
self . assertMsgId ( " Translatable literal #9b " , po_contents )
2014-10-28 18:02:56 +08:00
self . assertNotIn ( ' ignored i18n comment #2 ' , po_contents )
self . assertNotIn ( ' ignored comment #2 ' , po_contents )
2013-01-21 02:07:10 +08:00
self . assertMsgId ( ' Translatable literal #9c ' , po_contents )
2014-10-28 18:02:56 +08:00
self . assertNotIn ( ' ignored comment #3 ' , po_contents )
self . assertNotIn ( ' ignored i18n comment #3 ' , po_contents )
2013-01-21 02:07:10 +08:00
self . assertMsgId ( ' Translatable literal #9d ' , po_contents )
2014-10-28 18:02:56 +08:00
self . assertNotIn ( ' ignored comment #4 ' , po_contents )
2013-01-21 02:07:10 +08:00
self . assertMsgId ( ' Translatable literal #9e ' , po_contents )
2014-10-28 18:02:56 +08:00
self . assertNotIn ( ' ignored comment #5 ' , po_contents )
2013-01-21 02:07:10 +08:00
2014-10-28 18:02:56 +08:00
self . assertNotIn ( ' ignored i18n comment #4 ' , po_contents )
2013-01-21 02:07:10 +08:00
self . assertMsgId ( ' Translatable literal #9f ' , po_contents )
2014-10-28 18:02:56 +08:00
self . assertIn ( ' #. Translators: valid i18n comment #5 ' , po_contents )
2013-01-21 02:07:10 +08:00
self . assertMsgId ( ' Translatable literal #9g ' , po_contents )
2014-10-28 18:02:56 +08:00
self . assertIn ( ' #. Translators: valid i18n comment #6 ' , po_contents )
2013-01-21 02:07:10 +08:00
self . assertMsgId ( ' Translatable literal #9h ' , po_contents )
2014-10-28 18:02:56 +08:00
self . assertIn ( ' #. Translators: valid i18n comment #7 ' , po_contents )
2013-01-21 02:07:10 +08:00
self . assertMsgId ( ' Translatable literal #9i ' , po_contents )
six . assertRegex ( self , po_contents , r ' # \ ..+Translators: valid i18n comment #8 ' )
six . assertRegex ( self , po_contents , r ' # \ ..+Translators: valid i18n comment #9 ' )
self . assertMsgId ( " Translatable literal #9j " , po_contents )
2014-11-17 05:16:41 +08:00
def test_makemessages_find_files ( self ) :
"""
Test that find_files only discover files having the proper extensions .
"""
from django . core . management . commands . makemessages import Command
cmd = Command ( )
cmd . ignore_patterns = [ ' CVS ' , ' .* ' , ' *~ ' , ' *.pyc ' ]
cmd . symlinks = False
cmd . domain = ' django '
cmd . extensions = [ ' html ' , ' txt ' , ' py ' ]
cmd . verbosity = 0
cmd . locale_paths = [ ]
cmd . default_locale_path = os . path . join ( self . test_dir , ' locale ' )
found_files = cmd . find_files ( self . test_dir )
found_exts = set ( [ os . path . splitext ( tfile . file ) [ 1 ] for tfile in found_files ] )
self . assertEqual ( found_exts . difference ( { ' .py ' , ' .html ' , ' .txt ' } ) , set ( ) )
cmd . extensions = [ ' js ' ]
cmd . domain = ' djangojs '
found_files = cmd . find_files ( self . test_dir )
found_exts = set ( [ os . path . splitext ( tfile . file ) [ 1 ] for tfile in found_files ] )
self . assertEqual ( found_exts . difference ( { ' .js ' } ) , set ( ) )
2010-02-22 07:45:04 +08:00
class JavascriptExtractorTests ( ExtractorTests ) :
2013-10-23 18:09:29 +08:00
PO_FILE = ' locale/ %s /LC_MESSAGES/djangojs.po ' % LOCALE
2010-02-22 07:45:04 +08:00
def test_javascript_literals ( self ) :
os . chdir ( self . test_dir )
2014-10-18 18:00:38 +08:00
_ , po_contents = self . _run_makemessages ( domain = ' djangojs ' )
self . assertMsgId ( ' This literal should be included. ' , po_contents )
2014-11-11 16:40:03 +08:00
self . assertMsgId ( ' gettext_noop should, too. ' , po_contents )
2014-10-18 18:00:38 +08:00
self . assertMsgId ( ' This one as well. ' , po_contents )
self . assertMsgId ( r ' He said, \ " hello \ " . ' , po_contents )
self . assertMsgId ( " okkkk " , po_contents )
self . assertMsgId ( " TEXT " , po_contents )
self . assertMsgId ( " It ' s at http://example.com " , po_contents )
self . assertMsgId ( " String " , po_contents )
self . assertMsgId ( " /* but this one will be too */ ' cause there is no way of telling... " , po_contents )
self . assertMsgId ( " foo " , po_contents )
self . assertMsgId ( " bar " , po_contents )
self . assertMsgId ( " baz " , po_contents )
self . assertMsgId ( " quz " , po_contents )
self . assertMsgId ( " foobar " , po_contents )
@override_settings (
STATIC_ROOT = os . path . join ( this_directory , ' commands ' , ' static/ ' ) ,
MEDIA_ROOT = os . path . join ( this_directory , ' commands ' , ' media_root/ ' ) )
def test_media_static_dirs_ignored ( self ) :
"""
Regression test for #23583.
"""
_ , po_contents = self . _run_makemessages ( domain = ' djangojs ' )
self . assertMsgId ( " Static content inside app should be included. " , po_contents )
self . assertNotMsgId ( " Content from STATIC_ROOT should not be included " , po_contents )
2010-02-22 07:45:04 +08:00
2014-10-27 16:35:01 +08:00
@override_settings ( STATIC_ROOT = None , MEDIA_ROOT = ' ' )
def test_default_root_settings ( self ) :
"""
Regression test for #23717.
"""
_ , po_contents = self . _run_makemessages ( domain = ' djangojs ' )
self . assertMsgId ( " Static content inside app should be included. " , po_contents )
2013-11-03 12:36:09 +08:00
2010-02-22 07:45:04 +08:00
class IgnoredExtractorTests ( ExtractorTests ) :
2014-08-09 04:47:35 +08:00
def test_ignore_directory ( self ) :
out , po_contents = self . _run_makemessages ( ignore_patterns = [
os . path . join ( ' ignore_dir ' , ' * ' ) ,
] )
2014-10-28 18:02:56 +08:00
self . assertIn ( " ignoring directory ignore_dir " , out )
2014-08-09 04:47:35 +08:00
self . assertMsgId ( ' This literal should be included. ' , po_contents )
self . assertNotMsgId ( ' This should be ignored. ' , po_contents )
def test_ignore_subdirectory ( self ) :
out , po_contents = self . _run_makemessages ( ignore_patterns = [
' templates/*/ignore.html ' ,
' templates/subdir/* ' ,
] )
2014-10-28 18:02:56 +08:00
self . assertIn ( " ignoring directory subdir " , out )
2014-08-09 04:47:35 +08:00
self . assertNotMsgId ( ' This subdir should be ignored too. ' , po_contents )
def test_ignore_file_patterns ( self ) :
out , po_contents = self . _run_makemessages ( ignore_patterns = [
' xxx_* ' ,
] )
2014-10-28 18:02:56 +08:00
self . assertIn ( " ignoring file xxx_ignored.html " , out )
2014-08-09 04:47:35 +08:00
self . assertNotMsgId ( ' This should be ignored too. ' , po_contents )
2010-02-22 07:45:04 +08:00
2014-07-15 17:10:50 +08:00
@override_settings (
2014-10-18 18:00:38 +08:00
STATIC_ROOT = os . path . join ( this_directory , ' commands ' , ' static/ ' ) ,
2014-07-15 17:10:50 +08:00
MEDIA_ROOT = os . path . join ( this_directory , ' commands ' , ' media_root/ ' ) )
def test_media_static_dirs_ignored ( self ) :
2014-08-09 04:47:35 +08:00
out , _ = self . _run_makemessages ( )
2014-10-18 18:00:38 +08:00
self . assertIn ( " ignoring directory static " , out )
2014-08-09 04:47:35 +08:00
self . assertIn ( " ignoring directory media_root " , out )
2014-07-15 17:10:50 +08:00
2010-02-22 07:45:04 +08:00
class SymlinkExtractorTests ( ExtractorTests ) :
def setUp ( self ) :
2013-10-28 21:17:48 +08:00
super ( SymlinkExtractorTests , self ) . setUp ( )
2010-02-22 07:45:04 +08:00
self . symlinked_dir = os . path . join ( self . test_dir , ' templates_symlinked ' )
def tearDown ( self ) :
super ( SymlinkExtractorTests , self ) . tearDown ( )
os . chdir ( self . test_dir )
try :
os . remove ( self . symlinked_dir )
except OSError :
pass
os . chdir ( self . _cwd )
def test_symlink ( self ) :
2013-10-02 17:57:56 +08:00
# On Python < 3.2 os.symlink() exists only on Unix
2010-02-22 07:45:04 +08:00
if hasattr ( os , ' symlink ' ) :
if os . path . exists ( self . symlinked_dir ) :
2011-03-03 23:04:39 +08:00
self . assertTrue ( os . path . islink ( self . symlinked_dir ) )
2010-02-22 07:45:04 +08:00
else :
2013-10-02 17:57:56 +08:00
# On Python >= 3.2) os.symlink() exists always but then can
# fail at runtime when user hasn't the needed permissions on
# WIndows versions that support symbolink links (>= 6/Vista).
# See Python issue 9333 (http://bugs.python.org/issue9333).
# Skip the test in that case
try :
os . symlink ( os . path . join ( self . test_dir , ' templates ' ) , self . symlinked_dir )
except ( OSError , NotImplementedError ) :
raise SkipTest ( " os.symlink() is available on this OS but can ' t be used by this user. " )
2010-02-22 07:45:04 +08:00
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 , symlinks = True )
2011-03-03 23:04:39 +08:00
self . assertTrue ( os . path . exists ( self . PO_FILE ) )
2011-12-11 08:07:06 +08:00
with open ( self . PO_FILE , ' r ' ) as fp :
2012-12-08 18:13:52 +08:00
po_contents = force_text ( fp . read ( ) )
2011-12-11 08:07:06 +08:00
self . assertMsgId ( ' This literal should be included. ' , po_contents )
2014-10-28 18:02:56 +08:00
self . assertIn ( ' templates_symlinked/test.html ' , po_contents )
2010-02-22 07:45:04 +08:00
class CopyPluralFormsExtractorTests ( ExtractorTests ) :
2014-03-24 21:03:06 +08:00
2013-06-23 05:39:14 +08:00
PO_FILE_ES = ' locale/es/LC_MESSAGES/django.po '
def tearDown ( self ) :
2013-10-21 12:17:52 +08:00
super ( CopyPluralFormsExtractorTests , self ) . tearDown ( )
2013-06-23 05:39:14 +08:00
os . chdir ( self . test_dir )
try :
self . _rmrf ( ' locale/es ' )
except OSError :
pass
os . chdir ( self . _cwd )
2010-02-22 07:45:04 +08:00
def test_copy_plural_forms ( self ) :
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 )
2011-03-03 23:04:39 +08:00
self . assertTrue ( os . path . exists ( self . PO_FILE ) )
2011-12-11 08:07:06 +08:00
with open ( self . PO_FILE , ' r ' ) as fp :
2012-12-08 18:13:52 +08:00
po_contents = force_text ( fp . read ( ) )
2014-10-28 18:02:56 +08:00
self . assertIn ( ' Plural-Forms: nplurals=2; plural=(n != 1) ' , po_contents )
2010-11-04 20:08:37 +08:00
2013-06-23 05:39:14 +08:00
def test_override_plural_forms ( self ) :
""" Ticket #20311. """
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ ' es ' ] , extensions = [ ' djtpl ' ] , verbosity = 0 )
2013-06-23 05:39:14 +08:00
self . assertTrue ( os . path . exists ( self . PO_FILE_ES ) )
2013-10-21 11:22:32 +08:00
with io . open ( self . PO_FILE_ES , ' r ' , encoding = ' utf-8 ' ) as fp :
po_contents = fp . read ( )
2013-06-23 05:39:14 +08:00
found = re . findall ( r ' ^(?P<value> " Plural-Forms.+? \\ n " ) \ s*$ ' , po_contents , re . MULTILINE | re . DOTALL )
self . assertEqual ( 1 , len ( found ) )
2010-11-04 20:08:37 +08:00
class NoWrapExtractorTests ( ExtractorTests ) :
def test_no_wrap_enabled ( self ) :
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 , no_wrap = True )
2011-03-03 23:04:39 +08:00
self . assertTrue ( os . path . exists ( self . PO_FILE ) )
2011-12-11 08:07:06 +08:00
with open ( self . PO_FILE , ' r ' ) as fp :
2012-12-08 18:13:52 +08:00
po_contents = force_text ( fp . read ( ) )
2011-12-11 08:07:06 +08:00
self . assertMsgId ( ' This literal should also be included wrapped or not wrapped depending on the use of the --no-wrap option. ' , po_contents )
2010-11-04 20:08:37 +08:00
def test_no_wrap_disabled ( self ) :
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 , no_wrap = False )
2011-03-03 23:04:39 +08:00
self . assertTrue ( os . path . exists ( self . PO_FILE ) )
2011-12-11 08:07:06 +08:00
with open ( self . PO_FILE , ' r ' ) as fp :
2012-12-08 18:13:52 +08:00
po_contents = force_text ( fp . read ( ) )
2011-12-11 08:07:06 +08:00
self . assertMsgId ( ' " " \n " This literal should also be included wrapped or not wrapped depending on the " \n " use of the --no-wrap option. " ' , po_contents , use_quotes = False )
2011-11-11 21:07:14 +08:00
2013-10-02 07:23:36 +08:00
class LocationCommentsTests ( ExtractorTests ) :
2011-11-11 21:07:14 +08:00
def test_no_location_enabled ( self ) :
2013-10-02 07:23:36 +08:00
""" Behavior is correct if --no-location switch is specified. See #16903. """
2011-11-11 21:07:14 +08:00
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 , no_location = True )
2011-11-11 21:07:14 +08:00
self . assertTrue ( os . path . exists ( self . PO_FILE ) )
2013-11-08 22:44:37 +08:00
self . assertLocationCommentNotPresent ( self . PO_FILE , 55 , ' templates ' , ' test.html.py ' )
2011-11-11 21:07:14 +08:00
def test_no_location_disabled ( self ) :
2013-10-02 07:23:36 +08:00
""" Behavior is correct if --no-location switch isn ' t specified. """
2011-11-11 21:07:14 +08:00
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 , no_location = False )
2011-11-11 21:07:14 +08:00
self . assertTrue ( os . path . exists ( self . PO_FILE ) )
2013-11-08 22:44:37 +08:00
# #16903 -- Standard comment with source file relative path should be present
self . assertLocationCommentPresent ( self . PO_FILE , 55 , ' templates ' , ' test.html ' )
# #21208 -- Leaky paths in comments on Windows e.g. #: path\to\file.html.py:123
self . assertLocationCommentNotPresent ( self . PO_FILE , None , ' templates ' , ' test.html.py ' )
2013-01-17 02:36:22 +08:00
class KeepPotFileExtractorTests ( ExtractorTests ) :
2013-10-23 18:09:29 +08:00
POT_FILE = ' locale/django.pot '
2013-01-17 03:21:47 +08:00
2013-01-17 02:36:22 +08:00
def setUp ( self ) :
super ( KeepPotFileExtractorTests , self ) . setUp ( )
def tearDown ( self ) :
super ( KeepPotFileExtractorTests , self ) . tearDown ( )
os . chdir ( self . test_dir )
try :
os . unlink ( self . POT_FILE )
except OSError :
pass
os . chdir ( self . _cwd )
def test_keep_pot_disabled_by_default ( self ) :
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 )
2013-01-17 02:36:22 +08:00
self . assertFalse ( os . path . exists ( self . POT_FILE ) )
def test_keep_pot_explicitly_disabled ( self ) :
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 ,
2013-01-17 02:36:22 +08:00
keep_pot = False )
self . assertFalse ( os . path . exists ( self . POT_FILE ) )
def test_keep_pot_enabled ( self ) :
os . chdir ( self . test_dir )
2013-11-23 10:47:04 +08:00
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 ,
2013-01-17 02:36:22 +08:00
keep_pot = True )
self . assertTrue ( os . path . exists ( self . POT_FILE ) )
2012-06-07 17:23:25 +08:00
class MultipleLocaleExtractionTests ( ExtractorTests ) :
PO_FILE_PT = ' locale/pt/LC_MESSAGES/django.po '
PO_FILE_DE = ' locale/de/LC_MESSAGES/django.po '
LOCALES = [ ' pt ' , ' de ' , ' ch ' ]
def tearDown ( self ) :
os . chdir ( self . test_dir )
for locale in self . LOCALES :
try :
self . _rmrf ( ' locale/ %s ' % locale )
except OSError :
pass
os . chdir ( self . _cwd )
def test_multiple_locales ( self ) :
os . chdir ( self . test_dir )
2013-10-27 03:15:03 +08:00
management . call_command ( ' makemessages ' , locale = [ ' pt ' , ' de ' ] , verbosity = 0 )
2012-06-07 17:23:25 +08:00
self . assertTrue ( os . path . exists ( self . PO_FILE_PT ) )
self . assertTrue ( os . path . exists ( self . PO_FILE_DE ) )
2013-11-30 17:53:08 +08:00
2014-03-24 21:03:06 +08:00
class ExcludedLocaleExtractionTests ( ExtractorTests ) :
LOCALES = [ ' en ' , ' fr ' , ' it ' ]
PO_FILE = ' locale/ %s /LC_MESSAGES/django.po '
2014-07-15 17:10:50 +08:00
test_dir = os . path . abspath ( os . path . join ( this_directory , ' exclude ' ) )
2014-03-24 21:03:06 +08:00
def _set_times_for_all_po_files ( self ) :
"""
Set access and modification times to the Unix epoch time for all the . po files .
"""
for locale in self . LOCALES :
os . utime ( self . PO_FILE % locale , ( 0 , 0 ) )
def setUp ( self ) :
super ( ExcludedLocaleExtractionTests , self ) . setUp ( )
os . chdir ( self . test_dir ) # ExtractorTests.tearDown() takes care of restoring.
shutil . copytree ( ' canned_locale ' , ' locale ' )
self . _set_times_for_all_po_files ( )
self . addCleanup ( self . _rmrf , os . path . join ( self . test_dir , ' locale ' ) )
2014-05-01 15:03:24 +08:00
def test_command_help ( self ) :
2014-11-29 06:47:53 +08:00
with captured_stdout ( ) , captured_stderr ( ) :
2014-05-01 15:03:24 +08:00
# `call_command` bypasses the parser; by calling
# `execute_from_command_line` with the help subcommand we
# ensure that there are no issues with the parser itself.
execute_from_command_line ( [ ' django-admin ' , ' help ' , ' makemessages ' ] )
2014-03-24 21:03:06 +08:00
def test_one_locale_excluded ( self ) :
management . call_command ( ' makemessages ' , exclude = [ ' it ' ] , stdout = StringIO ( ) )
self . assertRecentlyModified ( self . PO_FILE % ' en ' )
self . assertRecentlyModified ( self . PO_FILE % ' fr ' )
self . assertNotRecentlyModified ( self . PO_FILE % ' it ' )
def test_multiple_locales_excluded ( self ) :
management . call_command ( ' makemessages ' , exclude = [ ' it ' , ' fr ' ] , stdout = StringIO ( ) )
self . assertRecentlyModified ( self . PO_FILE % ' en ' )
self . assertNotRecentlyModified ( self . PO_FILE % ' fr ' )
self . assertNotRecentlyModified ( self . PO_FILE % ' it ' )
def test_one_locale_excluded_with_locale ( self ) :
management . call_command ( ' makemessages ' , locale = [ ' en ' , ' fr ' ] , exclude = [ ' fr ' ] , stdout = StringIO ( ) )
self . assertRecentlyModified ( self . PO_FILE % ' en ' )
self . assertNotRecentlyModified ( self . PO_FILE % ' fr ' )
self . assertNotRecentlyModified ( self . PO_FILE % ' it ' )
def test_multiple_locales_excluded_with_locale ( self ) :
management . call_command ( ' makemessages ' , locale = [ ' en ' , ' fr ' , ' it ' ] , exclude = [ ' fr ' , ' it ' ] ,
stdout = StringIO ( ) )
self . assertRecentlyModified ( self . PO_FILE % ' en ' )
self . assertNotRecentlyModified ( self . PO_FILE % ' fr ' )
self . assertNotRecentlyModified ( self . PO_FILE % ' it ' )
2013-11-30 17:53:08 +08:00
class CustomLayoutExtractionTests ( ExtractorTests ) :
2014-03-24 21:03:06 +08:00
2013-11-30 17:53:08 +08:00
def setUp ( self ) :
self . _cwd = os . getcwd ( )
2014-07-15 17:10:50 +08:00
self . test_dir = os . path . join ( this_directory , ' project_dir ' )
2013-11-30 17:53:08 +08:00
def test_no_locale_raises ( self ) :
os . chdir ( self . test_dir )
with six . assertRaisesRegex ( self , management . CommandError ,
" Unable to find a locale path to store translations for file " ) :
management . call_command ( ' makemessages ' , locale = LOCALE , verbosity = 0 )
@override_settings (
LOCALE_PATHS = ( os . path . join (
2014-07-15 17:10:50 +08:00
this_directory , ' project_dir ' , ' project_locale ' ) , )
2013-11-30 17:53:08 +08:00
)
def test_project_locale_paths ( self ) :
"""
Test that :
* translations for an app containing a locale folder are stored in that folder
* translations outside of that app are in LOCALE_PATHS [ 0 ]
"""
os . chdir ( self . test_dir )
self . addCleanup ( shutil . rmtree ,
os . path . join ( settings . LOCALE_PATHS [ 0 ] , LOCALE ) , True )
self . addCleanup ( shutil . rmtree ,
os . path . join ( self . test_dir , ' app_with_locale ' , ' locale ' , LOCALE ) , True )
management . call_command ( ' makemessages ' , locale = [ LOCALE ] , verbosity = 0 )
project_de_locale = os . path . join (
self . test_dir , ' project_locale ' , ' de ' , ' LC_MESSAGES ' , ' django.po ' )
app_de_locale = os . path . join (
self . test_dir , ' app_with_locale ' , ' locale ' , ' de ' , ' LC_MESSAGES ' , ' django.po ' )
self . assertTrue ( os . path . exists ( project_de_locale ) )
self . assertTrue ( os . path . exists ( app_de_locale ) )
with open ( project_de_locale , ' r ' ) as fp :
po_contents = force_text ( fp . read ( ) )
self . assertMsgId ( ' This app has no locale directory ' , po_contents )
self . assertMsgId ( ' This is a project-level string ' , po_contents )
with open ( app_de_locale , ' r ' ) as fp :
po_contents = force_text ( fp . read ( ) )
self . assertMsgId ( ' This app has a locale directory ' , po_contents )