Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
dfb04bc4
Commit
dfb04bc4
authored
Dec 20, 2013
by
Ned Batchelder
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2017 from edx/ned/i18n-minor-improvements
Minor i18n improvements
parents
6c4aae73
c37ab385
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
110 additions
and
100 deletions
+110
-100
cms/urls.py
+2
-1
i18n/config.py
+1
-1
i18n/converter.py
+15
-7
i18n/dummy.py
+17
-17
i18n/execute.py
+4
-3
i18n/extract.py
+28
-23
i18n/generate.py
+13
-10
i18n/make_dummy.py
+1
-5
i18n/tests/__init__.py
+0
-6
i18n/tests/test_config.py
+1
-1
i18n/tests/test_converter.py
+8
-4
i18n/tests/test_dummy.py
+14
-13
i18n/tests/test_validate.py
+2
-5
i18n/transifex.py
+2
-3
lms/urls.py
+2
-1
No files found.
cms/urls.py
View file @
dfb04bc4
...
@@ -84,7 +84,8 @@ urlpatterns += patterns(
...
@@ -84,7 +84,8 @@ urlpatterns += patterns(
js_info_dict
=
{
js_info_dict
=
{
'domain'
:
'djangojs'
,
'domain'
:
'djangojs'
,
'packages'
:
(
'cms'
,),
# No packages needed, we get LOCALE_PATHS anyway.
'packages'
:
(),
}
}
urlpatterns
+=
patterns
(
''
,
urlpatterns
+=
patterns
(
''
,
...
...
i18n/config.py
View file @
dfb04bc4
...
@@ -11,7 +11,7 @@ BASE_DIR = path(__file__).abspath().dirname().joinpath('..').normpath()
...
@@ -11,7 +11,7 @@ BASE_DIR = path(__file__).abspath().dirname().joinpath('..').normpath()
LOCALE_DIR
=
BASE_DIR
.
joinpath
(
'conf'
,
'locale'
)
LOCALE_DIR
=
BASE_DIR
.
joinpath
(
'conf'
,
'locale'
)
class
Configuration
:
class
Configuration
(
object
)
:
"""
"""
# Reads localization configuration in json format
# Reads localization configuration in json format
...
...
i18n/converter.py
View file @
dfb04bc4
import
re
import
re
import
itertools
import
itertools
class
Converter
:
class
Converter
(
object
)
:
"""Converter is an abstract class that transforms strings.
"""Converter is an abstract class that transforms strings.
It hides embedded tags (HTML or Python sequences) from transformation
It hides embedded tags (HTML or Python sequences) from transformation
To implement Converter, provide implementation for inner_convert_string()
To implement Converter, provide implementation for inner_convert_string()
Strategy:
Strategy:
...
@@ -16,16 +16,25 @@ class Converter:
...
@@ -16,16 +16,25 @@ class Converter:
3. re-insert the extracted tags
3. re-insert the extracted tags
"""
"""
# matches tags like these:
# matches tags like these:
# HTML: <B>, </B>, <BR/>, <textformat leading="10">
# HTML: <B>, </B>, <BR/>, <textformat leading="10">
# Python: %(date)s, %(name)s
# Python: %(date)s, %(name)s
tag_pattern
=
re
.
compile
(
r'(<[-\w" .:?=/]*>)|({[^}]*})|(
%
\([^)]*\)\w)'
,
re
.
I
)
tag_pattern
=
re
.
compile
(
r'''
(<[-\w" .:?=/]*>) | # <tag>
({[^}]*}) | # {tag}
(
%
\([^)]*\)\w) | #
%(tag)
s
(&\w+;) | # &entity;
(&\#\d+;) | # Ӓ
(&\#x[0-9a-f]+;) # ꯍ
'''
,
re
.
IGNORECASE
|
re
.
VERBOSE
)
def
convert
(
self
,
string
):
def
convert
(
self
,
string
):
"""Returns: a converted tagged string
"""Returns: a converted tagged string
param: string (contains html tags)
param: string (contains html tags)
Don't replace characters inside tags
Don't replace characters inside tags
"""
"""
(
string
,
tags
)
=
self
.
detag_string
(
string
)
(
string
,
tags
)
=
self
.
detag_string
(
string
)
...
@@ -35,7 +44,7 @@ class Converter:
...
@@ -35,7 +44,7 @@ class Converter:
def
detag_string
(
self
,
string
):
def
detag_string
(
self
,
string
):
"""Extracts tags from string.
"""Extracts tags from string.
returns (string, list) where
returns (string, list) where
string: string has tags replaced by indices (<BR>... => <0>, <1>, <2>, etc.)
string: string has tags replaced by indices (<BR>... => <0>, <1>, <2>, etc.)
list: list of the removed tags ('<BR>', '<I>', '</I>')
list: list of the removed tags ('<BR>', '<I>', '</I>')
...
@@ -62,4 +71,3 @@ class Converter:
...
@@ -62,4 +71,3 @@ class Converter:
def
inner_convert_string
(
self
,
string
):
def
inner_convert_string
(
self
,
string
):
return
string
# do nothing by default
return
string
# do nothing by default
i18n/dummy.py
View file @
dfb04bc4
...
@@ -34,8 +34,11 @@ TABLE = {'A': u'\xC0',
...
@@ -34,8 +34,11 @@ TABLE = {'A': u'\xC0',
'I'
:
U'
\xCC
'
,
'I'
:
U'
\xCC
'
,
'i'
:
u'
\xEF
'
,
'i'
:
u'
\xEF
'
,
'O'
:
u'
\xD8
'
,
'O'
:
u'
\xD8
'
,
'o'
:
u'
\xF6
'
,
'o'
:
u'
\xF8
'
,
'u'
:
u'
\xFC
'
'U'
:
u'
\xDB
'
,
'u'
:
u'
\xFC
'
,
'Y'
:
u'
\xDD
'
,
'y'
:
u'
\xFD
'
,
}
}
...
@@ -54,49 +57,47 @@ LOREM = ' Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed ' \
...
@@ -54,49 +57,47 @@ LOREM = ' Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed ' \
PAD_FACTOR
=
1.3
PAD_FACTOR
=
1.3
class
Dummy
(
Converter
):
class
Dummy
(
Converter
):
"""
"""
A string converter that generates dummy strings with fake accents
A string converter that generates dummy strings with fake accents
and lorem ipsum padding.
and lorem ipsum padding.
"""
"""
def
convert
(
self
,
string
):
def
convert
(
self
,
string
):
result
=
Converter
.
convert
(
self
,
string
)
result
=
Converter
.
convert
(
self
,
string
)
return
self
.
pad
(
result
)
return
self
.
pad
(
result
)
def
inner_convert_string
(
self
,
string
):
def
inner_convert_string
(
self
,
string
):
for
(
k
,
v
)
in
TABLE
.
items
():
for
k
,
v
in
TABLE
.
items
():
string
=
string
.
replace
(
k
,
v
)
string
=
string
.
replace
(
k
,
v
)
return
string
return
string
def
pad
(
self
,
string
):
def
pad
(
self
,
string
):
"""add some lorem ipsum text to the end of string"""
"""add some lorem ipsum text to the end of string"""
size
=
len
(
string
)
size
=
len
(
string
)
if
size
<
7
:
if
size
<
7
:
target
=
size
*
3
target
=
size
*
3
else
:
else
:
target
=
int
(
size
*
PAD_FACTOR
)
target
=
int
(
size
*
PAD_FACTOR
)
return
string
+
self
.
terminate
(
LOREM
[:(
target
-
size
)])
return
string
+
self
.
terminate
(
LOREM
[:(
target
-
size
)])
def
terminate
(
self
,
string
):
def
terminate
(
self
,
string
):
"""replaces the final char of string with #"""
"""replaces the final char of string with #"""
return
string
[:
-
1
]
+
'#'
return
string
[:
-
1
]
+
'#'
def
init_msgs
(
self
,
msgs
):
def
init_msgs
(
self
,
msgs
):
"""
"""
Make sure the first msg in msgs has a plural property.
Make sure the first msg in msgs has a plural property.
msgs is list of instances of polib.POEntry
msgs is list of instances of polib.POEntry
"""
"""
if
len
(
msgs
)
==
0
:
if
not
msgs
:
return
return
headers
=
msgs
[
0
]
.
get_property
(
'msgstr'
)
headers
=
msgs
[
0
]
.
get_property
(
'msgstr'
)
has_plural
=
len
([
header
for
header
in
headers
if
header
.
find
(
'Plural-Forms:'
)
==
0
])
>
0
has_plural
=
any
(
header
.
startswith
(
'Plural-Forms:'
)
for
header
in
headers
)
if
not
has_plural
:
if
not
has_plural
:
# Apply declaration for English pluralization rules
# Apply declaration for English pluralization rules
plural
=
"Plural-Forms: nplurals=2; plural=(n != 1);
\\
n"
plural
=
"Plural-Forms: nplurals=2; plural=(n != 1);
\\
n"
headers
.
append
(
plural
)
headers
.
append
(
plural
)
def
convert_msg
(
self
,
msg
):
def
convert_msg
(
self
,
msg
):
"""
"""
...
@@ -104,19 +105,18 @@ class Dummy (Converter):
...
@@ -104,19 +105,18 @@ class Dummy (Converter):
msg is an instance of polib.POEntry
msg is an instance of polib.POEntry
"""
"""
source
=
msg
.
msgid
source
=
msg
.
msgid
if
len
(
source
)
==
0
:
if
not
source
:
# don't translate empty string
# don't translate empty string
return
return
plural
=
msg
.
msgid_plural
plural
=
msg
.
msgid_plural
if
len
(
plural
)
>
0
:
if
plural
:
# translate singular and plural
# translate singular and plural
foreign_single
=
self
.
convert
(
source
)
foreign_single
=
self
.
convert
(
source
)
foreign_plural
=
self
.
convert
(
plural
)
foreign_plural
=
self
.
convert
(
plural
)
plural
=
{
'0'
:
self
.
final_newline
(
source
,
foreign_single
),
plural
=
{
'0'
:
self
.
final_newline
(
source
,
foreign_single
),
'1'
:
self
.
final_newline
(
plural
,
foreign_plural
)}
'1'
:
self
.
final_newline
(
plural
,
foreign_plural
)}
msg
.
msgstr_plural
=
plural
msg
.
msgstr_plural
=
plural
return
else
:
else
:
foreign
=
self
.
convert
(
source
)
foreign
=
self
.
convert
(
source
)
msg
.
msgstr
=
self
.
final_newline
(
source
,
foreign
)
msg
.
msgstr
=
self
.
final_newline
(
source
,
foreign
)
...
@@ -126,7 +126,7 @@ class Dummy (Converter):
...
@@ -126,7 +126,7 @@ class Dummy (Converter):
If last char of original is a newline, make sure translation
If last char of original is a newline, make sure translation
has a newline too.
has a newline too.
"""
"""
if
len
(
original
)
>
1
:
if
original
:
if
original
[
-
1
]
==
'
\n
'
and
translated
[
-
1
]
!=
'
\n
'
:
if
original
[
-
1
]
==
'
\n
'
and
translated
[
-
1
]
!=
'
\n
'
:
return
translated
+
'
\n
'
translated
+=
'
\n
'
return
translated
return
translated
i18n/execute.py
View file @
dfb04bc4
...
@@ -11,13 +11,13 @@ def execute(command, working_directory=BASE_DIR):
...
@@ -11,13 +11,13 @@ def execute(command, working_directory=BASE_DIR):
Output is ignored.
Output is ignored.
"""
"""
LOG
.
info
(
command
)
LOG
.
info
(
command
)
subprocess
.
c
all
(
command
.
split
(
' '
),
cwd
=
working_directory
)
subprocess
.
c
heck_output
(
command
.
split
(
' '
),
cwd
=
working_directory
,
stderr
=
subprocess
.
STDOUT
)
def
call
(
command
,
working_directory
=
BASE_DIR
):
def
call
(
command
,
working_directory
=
BASE_DIR
):
"""
"""
Executes shell command in a given working_directory.
Executes shell command in a given working_directory.
Command is a
string to pass to the shell
.
Command is a
list of strings to execute as a command line
.
Returns a tuple of two strings: (stdout, stderr)
Returns a tuple of two strings: (stdout, stderr)
"""
"""
...
@@ -25,7 +25,8 @@ def call(command, working_directory=BASE_DIR):
...
@@ -25,7 +25,8 @@ def call(command, working_directory=BASE_DIR):
p
=
subprocess
.
Popen
(
command
,
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
PIPE
,
cwd
=
working_directory
)
p
=
subprocess
.
Popen
(
command
,
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
PIPE
,
cwd
=
working_directory
)
out
,
err
=
p
.
communicate
()
out
,
err
=
p
.
communicate
()
return
(
out
,
err
)
return
(
out
,
err
)
def
create_dir_if_necessary
(
pathname
):
def
create_dir_if_necessary
(
pathname
):
dirname
=
os
.
path
.
dirname
(
pathname
)
dirname
=
os
.
path
.
dirname
(
pathname
)
if
not
os
.
path
.
exists
(
dirname
):
if
not
os
.
path
.
exists
(
dirname
):
...
...
i18n/extract.py
View file @
dfb04bc4
#!/usr/bin/env python
#!/usr/bin/env python
"""
"""
See https://edx-wiki.atlassian.net/wiki/display/ENG/PO+File+workflow
See https://edx-wiki.atlassian.net/wiki/display/ENG/PO+File+workflow
This task extracts all English strings from all source code
This task extracts all English strings from all source code
and produces three human-readable files:
and produces three human-readable files:
conf/locale/en/LC_MESSAGES/django-partial.po
conf/locale/en/LC_MESSAGES/django-partial.po
conf/locale/en/LC_MESSAGES/djangojs.po
conf/locale/en/LC_MESSAGES/djangojs.po
conf/locale/en/LC_MESSAGES/mako.po
conf/locale/en/LC_MESSAGES/mako.po
This task will clobber any existing django.po file.
This task will clobber any existing django.po file.
This is because django-admin.py makemessages hardcodes this filename
This is because django-admin.py makemessages hardcodes this filename
and it cannot be overridden.
and it cannot be overridden.
"""
"""
import
os
,
sys
,
logging
import
os
,
sys
,
logging
...
@@ -34,7 +34,7 @@ SOURCE_WARN = 'This English source file is machine-generated. Do not check it in
...
@@ -34,7 +34,7 @@ SOURCE_WARN = 'This English source file is machine-generated. Do not check it in
LOG
=
logging
.
getLogger
(
__name__
)
LOG
=
logging
.
getLogger
(
__name__
)
def
main
():
def
main
():
logging
.
basicConfig
(
stream
=
sys
.
stdout
,
level
=
logging
.
INFO
)
logging
.
basicConfig
(
stream
=
sys
.
stdout
,
level
=
logging
.
INFO
)
create_dir_if_necessary
(
LOCALE_DIR
)
create_dir_if_necessary
(
LOCALE_DIR
)
source_msgs_dir
=
CONFIGURATION
.
source_messages_dir
source_msgs_dir
=
CONFIGURATION
.
source_messages_dir
...
@@ -44,23 +44,28 @@ def main ():
...
@@ -44,23 +44,28 @@ def main ():
for
filename
in
generated_files
:
for
filename
in
generated_files
:
remove_file
(
source_msgs_dir
.
joinpath
(
filename
))
remove_file
(
source_msgs_dir
.
joinpath
(
filename
))
# Extract strings from mako templates.
# Extract strings from mako templates
babel_mako_cmd
=
'pybabel extract -F
%
s -c "TRANSLATORS:" . -o
%
s'
%
(
BABEL_CONFIG
,
BABEL_OUT
)
babel_mako_cmd
=
'pybabel extract -F
%
s -c "TRANSLATORS:" . -o
%
s'
%
(
BABEL_CONFIG
,
BABEL_OUT
)
# Extract strings from django source files
# Extract strings from django source files.
make_django_cmd
=
'django-admin.py makemessages -l en --ignore=src/* --ignore=i18n/* '
\
make_django_cmd
=
(
+
'--extension html'
'django-admin.py makemessages -l en --ignore=src/* --ignore=i18n/* '
'--extension html'
# Extract strings from javascript source files
)
make_djangojs_cmd
=
'django-admin.py makemessages -l en -d djangojs --ignore=src/* '
\
# Extract strings from Javascript source files.
+
'--ignore=i18n/* --extension js'
make_djangojs_cmd
=
(
'django-admin.py makemessages -l en --ignore=src/* --ignore=i18n/* '
'-d djangojs --extension js'
)
execute
(
babel_mako_cmd
,
working_directory
=
BASE_DIR
)
execute
(
babel_mako_cmd
,
working_directory
=
BASE_DIR
)
execute
(
make_django_cmd
,
working_directory
=
BASE_DIR
)
execute
(
make_django_cmd
,
working_directory
=
BASE_DIR
)
# makemessages creates 'django.po'. This filename is hardcoded.
# makemessages creates 'django.po'. This filename is hardcoded.
# Rename it to django-partial.po to enable merging into django.po later.
# Rename it to django-partial.po to enable merging into django.po later.
os
.
rename
(
source_msgs_dir
.
joinpath
(
'django.po'
),
os
.
rename
(
source_msgs_dir
.
joinpath
(
'django-partial.po'
))
source_msgs_dir
.
joinpath
(
'django.po'
),
source_msgs_dir
.
joinpath
(
'django-partial.po'
)
)
execute
(
make_djangojs_cmd
,
working_directory
=
BASE_DIR
)
execute
(
make_djangojs_cmd
,
working_directory
=
BASE_DIR
)
for
filename
in
generated_files
:
for
filename
in
generated_files
:
...
@@ -101,7 +106,7 @@ def fix_header(po):
...
@@ -101,7 +106,7 @@ def fix_header(po):
(
'FIRST AUTHOR <EMAIL@ADDRESS>'
,
(
'FIRST AUTHOR <EMAIL@ADDRESS>'
,
'EdX Team <info@edx.org>'
)
'EdX Team <info@edx.org>'
)
)
)
for
(
src
,
dest
)
in
fixes
:
for
src
,
dest
in
fixes
:
header
=
header
.
replace
(
src
,
dest
)
header
=
header
.
replace
(
src
,
dest
)
po
.
header
=
header
po
.
header
=
header
...
@@ -112,12 +117,12 @@ def fix_header(po):
...
@@ -112,12 +117,12 @@ def fix_header(po):
u'Content-Transfer-Encoding': u'8bit',
u'Content-Transfer-Encoding': u'8bit',
u'Project-Id-Version': u'PACKAGE VERSION',
u'Project-Id-Version': u'PACKAGE VERSION',
u'Report-Msgid-Bugs-To': u'',
u'Report-Msgid-Bugs-To': u'',
u'Last-Translator': u'FULL NAME <EMAIL@ADDRESS>',
u'Last-Translator': u'FULL NAME <EMAIL@ADDRESS>',
u'Language-Team': u'LANGUAGE <LL@li.org>',
u'Language-Team': u'LANGUAGE <LL@li.org>',
u'POT-Creation-Date': u'2013-04-25 14:14-0400',
u'POT-Creation-Date': u'2013-04-25 14:14-0400',
u'Content-Type': u'text/plain; charset=UTF-8',
u'Content-Type': u'text/plain; charset=UTF-8',
u'MIME-Version': u'1.0'}
u'MIME-Version': u'1.0'}
"""
"""
def
fix_metadata
(
po
):
def
fix_metadata
(
po
):
"""
"""
...
@@ -146,7 +151,7 @@ def is_key_string(string):
...
@@ -146,7 +151,7 @@ def is_key_string(string):
returns True if string is a key string.
returns True if string is a key string.
Key strings begin with underscore.
Key strings begin with underscore.
"""
"""
return
len
(
string
)
>
1
and
string
[
0
]
==
'_'
return
len
(
string
)
>
1
and
string
[
0
]
==
'_'
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
main
()
main
()
i18n/generate.py
View file @
dfb04bc4
#!/usr/bin/env python
#!/usr/bin/env python
"""
"""
See https://edx-wiki.atlassian.net/wiki/display/ENG/PO+File+workflow
See https://edx-wiki.atlassian.net/wiki/display/ENG/PO+File+workflow
This task merges and compiles the human-readable .po files on the
local filesystem into machine-readable .mo files. This is typically
necessary as part of the build process since these .mo files are
needed by Django when serving the web app.
This task merges and compiles the human-readable .pofiles on the
The configuration file (in edx-platform/conf/locale/config) specifies which
local filesystem into machine-readable .mofiles. This is typically
languages to generate.
necessary as part of the build process since these .mofiles are
needed by Django when serving the web app.
The configuration file (in edx-platform/conf/locale/config) specifies which
languages to generate.
"""
"""
import
os
,
sys
,
logging
import
os
,
sys
,
logging
...
@@ -26,10 +26,13 @@ def merge(locale, target='django.po', fail_if_missing=True):
...
@@ -26,10 +26,13 @@ def merge(locale, target='django.po', fail_if_missing=True):
"""
"""
For the given locale, merge django-partial.po, messages.po, mako.po -> django.po
For the given locale, merge django-partial.po, messages.po, mako.po -> django.po
target is the resulting filename
target is the resulting filename
If fail_if_missing is True, and the files to be merged are missing,
throw an Exception.
If fail_if_missing is true, and the files to be merged are missing,
If fail_if_missing is False, and the files to be merged are missing,
throw an Exception, otherwise return silently.
If fail_if_missing is false, and the files to be merged are missing,
just return silently.
just return silently.
"""
"""
LOG
.
info
(
'Merging locale={0}'
.
format
(
locale
))
LOG
.
info
(
'Merging locale={0}'
.
format
(
locale
))
locale_directory
=
CONFIGURATION
.
get_messages_dir
(
locale
)
locale_directory
=
CONFIGURATION
.
get_messages_dir
(
locale
)
...
...
i18n/make_dummy.py
View file @
dfb04bc4
...
@@ -51,11 +51,7 @@ def new_filename(original_filename, new_locale):
...
@@ -51,11 +51,7 @@ def new_filename(original_filename, new_locale):
orig_dir
=
os
.
path
.
dirname
(
original_filename
)
orig_dir
=
os
.
path
.
dirname
(
original_filename
)
msgs_dir
=
os
.
path
.
basename
(
orig_dir
)
msgs_dir
=
os
.
path
.
basename
(
orig_dir
)
orig_file
=
os
.
path
.
basename
(
original_filename
)
orig_file
=
os
.
path
.
basename
(
original_filename
)
return
os
.
path
.
abspath
(
os
.
path
.
join
(
orig_dir
,
return
os
.
path
.
abspath
(
os
.
path
.
join
(
orig_dir
,
'../..'
,
new_locale
,
msgs_dir
,
orig_file
))
'../..'
,
new_locale
,
msgs_dir
,
orig_file
))
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
# required arg: file
# required arg: file
...
...
i18n/tests/__init__.py
View file @
dfb04bc4
from
test_config
import
TestConfiguration
from
test_extract
import
TestExtract
from
test_generate
import
TestGenerate
from
test_converter
import
TestConverter
from
test_dummy
import
TestDummy
import
test_validate
i18n/tests/test_config.py
View file @
dfb04bc4
...
@@ -17,7 +17,7 @@ class TestConfiguration(TestCase):
...
@@ -17,7 +17,7 @@ class TestConfiguration(TestCase):
config_filename
=
os
.
path
.
normpath
(
os
.
path
.
join
(
LOCALE_DIR
,
'no_such_file'
))
config_filename
=
os
.
path
.
normpath
(
os
.
path
.
join
(
LOCALE_DIR
,
'no_such_file'
))
with
self
.
assertRaises
(
Exception
):
with
self
.
assertRaises
(
Exception
):
Configuration
(
config_filename
)
Configuration
(
config_filename
)
def
test_valid_configuration
(
self
):
def
test_valid_configuration
(
self
):
"""
"""
Make sure we have a valid configuration file,
Make sure we have a valid configuration file,
...
...
i18n/tests/test_converter.py
View file @
dfb04bc4
...
@@ -3,7 +3,7 @@ from unittest import TestCase
...
@@ -3,7 +3,7 @@ from unittest import TestCase
import
converter
import
converter
class
UpcaseConverter
(
converter
.
Converter
):
class
UpcaseConverter
(
converter
.
Converter
):
"""
"""
Converts a string to uppercase. Just used for testing.
Converts a string to uppercase. Just used for testing.
"""
"""
...
@@ -22,7 +22,7 @@ class TestConverter(TestCase):
...
@@ -22,7 +22,7 @@ class TestConverter(TestCase):
Assert that embedded HTML and python tags are not converted.
Assert that embedded HTML and python tags are not converted.
"""
"""
c
=
UpcaseConverter
()
c
=
UpcaseConverter
()
test_cases
=
(
test_cases
=
[
# no tags
# no tags
(
'big bad wolf'
,
'BIG BAD WOLF'
),
(
'big bad wolf'
,
'BIG BAD WOLF'
),
# one html tag
# one html tag
...
@@ -36,7 +36,11 @@ class TestConverter(TestCase):
...
@@ -36,7 +36,11 @@ class TestConverter(TestCase):
# both kinds of tags
# both kinds of tags
(
'<strong>big</strong>
%(adjective)
s
%(noun)
s'
,
(
'<strong>big</strong>
%(adjective)
s
%(noun)
s'
,
'<strong>BIG</strong>
%(adjective)
s
%(noun)
s'
),
'<strong>BIG</strong>
%(adjective)
s
%(noun)
s'
),
)
# .format-style tags
for
(
source
,
expected
)
in
test_cases
:
(
'The {0} barn is {1!r}.'
,
'THE {0} BARN IS {1!r}.'
),
# HTML entities
(
'<b>© 2013 edX,  </b>'
,
'<b>© 2013 EDX,  </b>'
),
]
for
source
,
expected
in
test_cases
:
result
=
c
.
convert
(
source
)
result
=
c
.
convert
(
source
)
self
.
assertEquals
(
result
,
expected
)
self
.
assertEquals
(
result
,
expected
)
i18n/tests/test_dummy.py
View file @
dfb04bc4
...
@@ -18,23 +18,24 @@ class TestDummy(TestCase):
...
@@ -18,23 +18,24 @@ class TestDummy(TestCase):
Tests with a dummy converter (adds spurious accents to strings).
Tests with a dummy converter (adds spurious accents to strings).
Assert that embedded HTML and python tags are not converted.
Assert that embedded HTML and python tags are not converted.
"""
"""
test_cases
=
((
"hello my name is Bond, James Bond"
,
test_cases
=
[
u'h
\xe9
ll
\xf6
my n
\xe4
m
\xe9
\xef
s B
\xf6
nd, J
\xe4
m
\xe9
s B
\xf6
nd Lorem i#'
),
(
"hello my name is Bond, James Bond"
,
u'h
\xe9
ll
\xf8
m
\xfd
n
\xe4
m
\xe9
\xef
s B
\xf8
nd, J
\xe4
m
\xe9
s B
\xf8
nd Lorem i#'
),
(
'don
\'
t convert <a href="href">tag ids</a>'
,
u'd
\xf6
n
\'
t
\xe7\xf6
nv
\xe9
rt <a href="href">t
\xe4
g
\xef
ds</a> Lorem ipsu#'
),
(
'don
\'
t convert <a href="href">tag ids</a>'
,
u'd
\xf8
n
\'
t
\xe7\xf8
nv
\xe9
rt <a href="href">t
\xe4
g
\xef
ds</a> Lorem ipsu#'
),
(
'don
\'
t convert
%(name)
s tags on
%(date)
s'
,
u"d
\xf6
n't
\xe7\xf6
nv
\xe9
rt
%(name)
s t
\xe4
gs
\xf6
n
%(date)
s Lorem ips#"
)
(
'don
\'
t convert
%(name)
s tags on
%(date)
s'
,
)
u"d
\xf8
n't
\xe7\xf8
nv
\xe9
rt
%(name)
s t
\xe4
gs
\xf8
n
%(date)
s Lorem ips#"
)
for
(
source
,
expected
)
in
test_cases
:
]
for
source
,
expected
in
test_cases
:
result
=
self
.
converter
.
convert
(
source
)
result
=
self
.
converter
.
convert
(
source
)
self
.
assertEquals
(
result
,
expected
)
self
.
assertEquals
(
result
,
expected
)
def
test_singular
(
self
):
def
test_singular
(
self
):
entry
=
POEntry
()
entry
=
POEntry
()
entry
.
msgid
=
'A lovely day for a cup of tea.'
entry
.
msgid
=
'A lovely day for a cup of tea.'
expected
=
u'
\xc0
l
\xf
6
v
\xe9
ly d
\xe4
y f
\xf6
r
\xe4
\xe7\xfc
p
\xf6
f t
\xe9\xe4
. Lorem i#'
expected
=
u'
\xc0
l
\xf
8
v
\xe9
l
\xfd
d
\xe4\xfd
f
\xf8
r
\xe4
\xe7\xfc
p
\xf8
f t
\xe9\xe4
. Lorem i#'
self
.
converter
.
convert_msg
(
entry
)
self
.
converter
.
convert_msg
(
entry
)
self
.
assertEquals
(
entry
.
msgstr
,
expected
)
self
.
assertEquals
(
entry
.
msgstr
,
expected
)
...
@@ -42,8 +43,8 @@ class TestDummy(TestCase):
...
@@ -42,8 +43,8 @@ class TestDummy(TestCase):
entry
=
POEntry
()
entry
=
POEntry
()
entry
.
msgid
=
'A lovely day for a cup of tea.'
entry
.
msgid
=
'A lovely day for a cup of tea.'
entry
.
msgid_plural
=
'A lovely day for some cups of tea.'
entry
.
msgid_plural
=
'A lovely day for some cups of tea.'
expected_s
=
u'
\xc0
l
\xf
6
v
\xe9
ly d
\xe4
y f
\xf6
r
\xe4
\xe7\xfc
p
\xf6
f t
\xe9\xe4
. Lorem i#'
expected_s
=
u'
\xc0
l
\xf
8
v
\xe9
l
\xfd
d
\xe4\xfd
f
\xf8
r
\xe4
\xe7\xfc
p
\xf8
f t
\xe9\xe4
. Lorem i#'
expected_p
=
u'
\xc0
l
\xf
6
v
\xe9
ly d
\xe4
y f
\xf6
r s
\xf6
m
\xe9
\xe7\xfc
ps
\xf6
f t
\xe9\xe4
. Lorem ip#'
expected_p
=
u'
\xc0
l
\xf
8
v
\xe9
l
\xfd
d
\xe4\xfd
f
\xf8
r s
\xf8
m
\xe9
\xe7\xfc
ps
\xf8
f t
\xe9\xe4
. Lorem ip#'
self
.
converter
.
convert_msg
(
entry
)
self
.
converter
.
convert_msg
(
entry
)
result
=
entry
.
msgstr_plural
result
=
entry
.
msgstr_plural
self
.
assertEquals
(
result
[
'0'
],
expected_s
)
self
.
assertEquals
(
result
[
'0'
],
expected_s
)
...
...
i18n/tests/test_validate.py
View file @
dfb04bc4
...
@@ -4,14 +4,14 @@ from nose.plugins.skip import SkipTest
...
@@ -4,14 +4,14 @@ from nose.plugins.skip import SkipTest
from
config
import
LOCALE_DIR
from
config
import
LOCALE_DIR
from
execute
import
call
from
execute
import
call
def
test_po_files
(
root
=
LOCALE_DIR
):
def
test_po_files
(
root
=
LOCALE_DIR
):
"""
"""
This is a generator. It yields all of the .po files under root, and tests each one.
This is a generator. It yields all of the .po files under root, and tests each one.
"""
"""
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
logging
.
basicConfig
(
stream
=
sys
.
stdout
,
level
=
logging
.
INFO
)
logging
.
basicConfig
(
stream
=
sys
.
stdout
,
level
=
logging
.
INFO
)
for
(
dirpath
,
dirnames
,
filenames
)
in
os
.
walk
(
root
):
for
(
dirpath
,
dirnames
,
filenames
)
in
os
.
walk
(
root
):
for
name
in
filenames
:
for
name
in
filenames
:
(
base
,
ext
)
=
os
.
path
.
splitext
(
name
)
(
base
,
ext
)
=
os
.
path
.
splitext
(
name
)
...
@@ -24,11 +24,8 @@ def validate_po_file(filename, log):
...
@@ -24,11 +24,8 @@ def validate_po_file(filename, log):
Call GNU msgfmt -c on each .po file to validate its format.
Call GNU msgfmt -c on each .po file to validate its format.
Any errors caught by msgfmt are logged to log.
Any errors caught by msgfmt are logged to log.
"""
"""
# Skip this test for now because it's very noisy
raise
SkipTest
()
# Use relative paths to make output less noisy.
# Use relative paths to make output less noisy.
rfile
=
os
.
path
.
relpath
(
filename
,
LOCALE_DIR
)
rfile
=
os
.
path
.
relpath
(
filename
,
LOCALE_DIR
)
(
out
,
err
)
=
call
([
'msgfmt'
,
'-c'
,
rfile
],
working_directory
=
LOCALE_DIR
)
(
out
,
err
)
=
call
([
'msgfmt'
,
'-c'
,
rfile
],
working_directory
=
LOCALE_DIR
)
if
err
!=
''
:
if
err
!=
''
:
log
.
warn
(
'
\n
'
+
err
)
log
.
warn
(
'
\n
'
+
err
)
i18n/transifex.py
View file @
dfb04bc4
...
@@ -27,7 +27,7 @@ def clean_translated_locales():
...
@@ -27,7 +27,7 @@ def clean_translated_locales():
for
locale
in
CONFIGURATION
.
locales
:
for
locale
in
CONFIGURATION
.
locales
:
if
locale
!=
CONFIGURATION
.
source_locale
:
if
locale
!=
CONFIGURATION
.
source_locale
:
clean_locale
(
locale
)
clean_locale
(
locale
)
def
clean_locale
(
locale
):
def
clean_locale
(
locale
):
"""
"""
Strips out the warning from all of a locale's translated po files
Strips out the warning from all of a locale's translated po files
...
@@ -58,7 +58,7 @@ def get_new_header(po):
...
@@ -58,7 +58,7 @@ def get_new_header(po):
return
TRANSIFEX_HEADER
%
team
return
TRANSIFEX_HEADER
%
team
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
if
len
(
sys
.
argv
)
<
2
:
if
len
(
sys
.
argv
)
<
2
:
raise
Exception
(
"missing argument: push or pull"
)
raise
Exception
(
"missing argument: push or pull"
)
arg
=
sys
.
argv
[
1
]
arg
=
sys
.
argv
[
1
]
if
arg
==
'push'
:
if
arg
==
'push'
:
...
@@ -67,4 +67,3 @@ if __name__ == '__main__':
...
@@ -67,4 +67,3 @@ if __name__ == '__main__':
pull
()
pull
()
else
:
else
:
raise
Exception
(
"unknown argument: (
%
s)"
%
arg
)
raise
Exception
(
"unknown argument: (
%
s)"
%
arg
)
lms/urls.py
View file @
dfb04bc4
...
@@ -72,7 +72,8 @@ urlpatterns += (
...
@@ -72,7 +72,8 @@ urlpatterns += (
js_info_dict
=
{
js_info_dict
=
{
'domain'
:
'djangojs'
,
'domain'
:
'djangojs'
,
'packages'
:
(
'lms'
,),
# No packages needed, we get LOCALE_PATHS anyway.
'packages'
:
(),
}
}
urlpatterns
+=
(
urlpatterns
+=
(
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment