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
ece123e9
Commit
ece123e9
authored
Feb 07, 2014
by
Ned Batchelder
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
More than one dummy language
parent
a60abede
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
114 additions
and
115 deletions
+114
-115
.gitignore
+2
-0
conf/locale/config.yaml
+4
-2
i18n/config.py
+1
-12
i18n/dummy.py
+96
-92
i18n/generate.py
+2
-1
i18n/tests/test_config.py
+1
-1
i18n/tests/test_dummy.py
+6
-6
lms/envs/common.py
+2
-1
No files found.
.gitignore
View file @
ece123e9
...
@@ -37,6 +37,8 @@ codekit-config.json
...
@@ -37,6 +37,8 @@ codekit-config.json
!djangojs.mo
!djangojs.mo
conf/locale/en/LC_MESSAGES/*.po
conf/locale/en/LC_MESSAGES/*.po
conf/locale/en/LC_MESSAGES/*.mo
conf/locale/en/LC_MESSAGES/*.mo
conf/locale/fake*/LC_MESSAGES/*.po
conf/locale/fake*/LC_MESSAGES/*.mo
conf/locale/messages.mo
conf/locale/messages.mo
### Testing artifacts
### Testing artifacts
...
...
conf/locale/config.yaml
View file @
ece123e9
...
@@ -51,8 +51,10 @@ locales:
...
@@ -51,8 +51,10 @@ locales:
-
zh_TW
# Chinese (Taiwan)
-
zh_TW
# Chinese (Taiwan)
# The locale used for fake-accented English, for testing.
# The locales used for fake-accented English, for testing.
dummy-locale
:
eo
dummy_locales
:
-
eo
-
fake2
# Directories we don't search for strings.
# Directories we don't search for strings.
ignore_dirs
:
ignore_dirs
:
...
...
i18n/config.py
View file @
ece123e9
...
@@ -17,6 +17,7 @@ class Configuration(object):
...
@@ -17,6 +17,7 @@ class Configuration(object):
Reads localization configuration in json format.
Reads localization configuration in json format.
"""
"""
DEFAULTS
=
{
DEFAULTS
=
{
'dummy_locales'
:
[],
'generate_merge'
:
{},
'generate_merge'
:
{},
'ignore_dirs'
:
[],
'ignore_dirs'
:
[],
'locales'
:
[
'en'
],
'locales'
:
[
'en'
],
...
@@ -42,18 +43,6 @@ class Configuration(object):
...
@@ -42,18 +43,6 @@ class Configuration(object):
return
self
.
_config
.
get
(
name
,
self
.
DEFAULTS
[
name
])
return
self
.
_config
.
get
(
name
,
self
.
DEFAULTS
[
name
])
raise
AttributeError
(
"Configuration has no such setting: {!r}"
.
format
(
name
))
raise
AttributeError
(
"Configuration has no such setting: {!r}"
.
format
(
name
))
@property
def
dummy_locale
(
self
):
"""
Returns a locale to use for the dummy text, e.g. 'eo'.
Throws exception if no dummy-locale is declared.
The locale is a string.
"""
dummy
=
self
.
_config
.
get
(
'dummy-locale'
,
None
)
if
not
dummy
:
raise
Exception
(
'Could not read dummy-locale from configuration file.'
)
return
dummy
def
get_messages_dir
(
self
,
locale
):
def
get_messages_dir
(
self
,
locale
):
"""
"""
Returns the name of the directory holding the po files for locale.
Returns the name of the directory holding the po files for locale.
...
...
i18n/dummy.py
View file @
ece123e9
...
@@ -31,50 +31,59 @@ from i18n.config import CONFIGURATION
...
@@ -31,50 +31,59 @@ from i18n.config import CONFIGURATION
from
i18n.execute
import
create_dir_if_necessary
from
i18n.execute
import
create_dir_if_necessary
from
i18n.converter
import
Converter
from
i18n.converter
import
Converter
# Substitute plain characters with accented lookalikes.
# http://tlt.its.psu.edu/suggestions/international/web/codehtml.html#accent
TABLE
=
{
'A'
:
u'À'
,
'a'
:
u'ä'
,
'b'
:
u'ß'
,
'C'
:
u'Ç'
,
'c'
:
u'ç'
,
'E'
:
u'É'
,
'e'
:
u'é'
,
'I'
:
u'Ì'
,
'i'
:
u'ï'
,
'O'
:
u'Ø'
,
'o'
:
u'ø'
,
'U'
:
u'Û'
,
'u'
:
u'ü'
,
'Y'
:
u'Ý'
,
'y'
:
u'ý'
,
}
# The print industry's standard dummy text, in use since the 1500s
# see http://www.lipsum.com/, then fed through a "fancy-text" converter.
# The string should start with a space, so that it joins nicely with the text
# that precedes it. The Lorem contains an apostrophe since French often does,
# and translated strings get put into single-quoted strings, which then break.
LOREM
=
" "
+
" "
.
join
(
# join and split just make the string easier here.
u"""
Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂
тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм
νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα
¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє
νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт
¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм ι∂
єѕт łαвσяυм.
"""
.
split
()
)
# To simulate more verbose languages (like German), pad the length of a string
class
BaseDummyConverter
(
Converter
):
# by a multiple of PAD_FACTOR
"""Base class for dummy converters.
PAD_FACTOR
=
1.33
String conversion goes through a character map, then gets padded.
"""
TABLE
=
{}
def
inner_convert_string
(
self
,
string
):
for
old
,
new
in
self
.
TABLE
.
items
():
string
=
string
.
replace
(
old
,
new
)
return
self
.
pad
(
string
)
def
pad
(
self
,
string
):
return
string
class
Dummy
(
Converter
):
def
convert_msg
(
self
,
msg
):
"""
Takes one POEntry object and converts it (adds a dummy translation to it)
msg is an instance of polib.POEntry
"""
source
=
msg
.
msgid
if
not
source
:
# don't translate empty string
return
plural
=
msg
.
msgid_plural
if
plural
:
# translate singular and plural
foreign_single
=
self
.
convert
(
source
)
foreign_plural
=
self
.
convert
(
plural
)
plural
=
{
'0'
:
self
.
final_newline
(
source
,
foreign_single
),
'1'
:
self
.
final_newline
(
plural
,
foreign_plural
),
}
msg
.
msgstr_plural
=
plural
else
:
foreign
=
self
.
convert
(
source
)
msg
.
msgstr
=
self
.
final_newline
(
source
,
foreign
)
def
final_newline
(
self
,
original
,
translated
):
""" Returns a new translated string.
If last char of original is a newline, make sure translation
has a newline too.
"""
if
original
:
if
original
[
-
1
]
==
'
\n
'
and
translated
[
-
1
]
!=
'
\n
'
:
translated
+=
'
\n
'
return
translated
class
Dummy
(
BaseDummyConverter
):
r"""
r"""
Creates new localization properties files in a dummy language.
Creates new localization properties files in a dummy language.
...
@@ -101,15 +110,35 @@ class Dummy(Converter):
...
@@ -101,15 +110,35 @@ class Dummy(Converter):
døn't çønvért <a href='href'>täg ïds</a> Ⱡσяєм ιρѕυ#
døn't çønvért <a href='href'>täg ïds</a> Ⱡσяєм ιρѕυ#
>>> print c.convert("don't convert
%(name)
s tags on
%(date)
s")
>>> print c.convert("don't convert
%(name)
s tags on
%(date)
s")
døn't çønvért
%(name)
s tägs øn
%(date)
s Ⱡσяєм ιρѕ#
døn't çønvért
%(name)
s tägs øn
%(date)
s Ⱡσяєм ιρѕ#
"""
"""
def
convert
(
self
,
string
):
# Substitute plain characters with accented lookalikes.
result
=
Converter
.
convert
(
self
,
string
)
# http://tlt.its.psu.edu/suggestions/international/web/codehtml.html#accent
return
self
.
pad
(
result
)
TABLE
=
dict
(
zip
(
u"AabCcEeIiOoUuYy"
,
u"ÀäßÇçÉéÌïÖöÛüÝý"
))
# The print industry's standard dummy text, in use since the 1500s
# see http://www.lipsum.com/, then fed through a "fancy-text" converter.
# The string should start with a space, so that it joins nicely with the text
# that precedes it. The Lorem contains an apostrophe since French often does,
# and translated strings get put into single-quoted strings, which then break.
LOREM
=
" "
+
" "
.
join
(
# join and split just make the string easier here.
u"""
Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α∂ιριѕι¢ιηg єłιт, ѕє∂ ∂σ єιυѕмσ∂
тємρσя ιη¢ι∂ι∂υηт υт łαвσяє єт ∂σłσяє мαgηα αłιqυα. υт єηιм α∂ мιηιм
νєηιαм, qυιѕ ησѕтяυ∂ єχєя¢ιтαтιση υłłαм¢σ łαвσяιѕ ηιѕι υт αłιqυιρ єχ єα
¢σммσ∂σ ¢σηѕєqυαт. ∂υιѕ αυтє ιяυяє ∂σłσя ιη яєρяєнєη∂єяιт ιη νσłυρтαтє
νєłιт єѕѕє ¢ιłłυм ∂σłσяє єυ ƒυgιαт ηυłłα ραяιαтυя. єχ¢єρтєυя ѕιηт σ¢¢αє¢αт
¢υρι∂αтαт ηση ρяσι∂єηт, ѕυηт ιη ¢υłρα qυι σƒƒι¢ια ∂єѕєяυηт мσłłιт αηιм ι∂
єѕт łαвσяυм.
"""
.
split
()
)
def
inner_convert_string
(
self
,
string
):
# To simulate more verbose languages (like German), pad the length of a string
for
k
,
v
in
TABLE
.
items
():
# by a multiple of PAD_FACTOR
string
=
string
.
replace
(
k
,
v
)
PAD_FACTOR
=
1.33
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"""
...
@@ -117,57 +146,32 @@ class Dummy(Converter):
...
@@ -117,57 +146,32 @@ class Dummy(Converter):
if
size
<
7
:
if
size
<
7
:
target
=
size
*
3
target
=
size
*
3
else
:
else
:
target
=
int
(
size
*
PAD_FACTOR
)
target
=
int
(
size
*
self
.
PAD_FACTOR
)
return
string
+
self
.
terminate
(
LOREM
[:(
target
-
size
)])
pad_len
=
target
-
size
-
1
return
string
+
self
.
LOREM
[:
pad_len
]
+
"#"
def
terminate
(
self
,
string
):
"""replaces the final char of string with #"""
return
string
[:
-
1
]
+
'#'
def
convert_msg
(
self
,
msg
):
class
Dummy2
(
BaseDummyConverter
):
"""
"""A second dummy converter.
Takes one POEntry object and converts it (adds a dummy translation to it)
msg is an instance of polib.POEntry
"""
source
=
msg
.
msgid
if
not
source
:
# don't translate empty string
return
plural
=
msg
.
msgid_plural
Like Dummy, but uses a different obvious but readable automatic conversion:
if
plural
:
Strikes-through many letters, and turns lower-case letters upside-down.
# translate singular and plural
foreign_single
=
self
.
convert
(
source
)
foreign_plural
=
self
.
convert
(
plural
)
plural
=
{
'0'
:
self
.
final_newline
(
source
,
foreign_single
),
'1'
:
self
.
final_newline
(
plural
,
foreign_plural
),
}
msg
.
msgstr_plural
=
plural
else
:
foreign
=
self
.
convert
(
source
)
msg
.
msgstr
=
self
.
final_newline
(
source
,
foreign
)
def
final_newline
(
self
,
original
,
translated
):
""" Returns a new translated string.
If last char of original is a newline, make sure translation
has a newline too.
"""
"""
if
original
:
TABLE
=
dict
(
zip
(
if
original
[
-
1
]
==
'
\n
'
and
translated
[
-
1
]
!=
'
\n
'
:
u"ABCDEGHIJKLOPRTUYZabcdefghijklmnopqrstuvwxyz"
,
translated
+=
'
\n
'
u"ȺɃȻĐɆǤĦƗɈꝀŁØⱣɌŦɄɎƵɐqɔpǝɟƃɥᴉɾʞlɯuødbɹsʇnʌʍxʎz"
return
translated
))
def
make_dummy
(
file
,
locale
):
def
make_dummy
(
file
name
,
locale
,
converter
):
"""
"""
Takes a source po file, reads it, and writes out a new po file
Takes a source po file, reads it, and writes out a new po file
in :param locale: containing a dummy translation.
in :param locale: containing a dummy translation.
"""
"""
if
not
path
(
file
)
.
exists
():
if
not
path
(
filename
)
.
exists
():
raise
IOError
(
'File does not exist:
%
s'
%
file
)
raise
IOError
(
'File does not exist:
%
r'
%
filename
)
pofile
=
polib
.
pofile
(
file
)
pofile
=
polib
.
pofile
(
filename
)
converter
=
Dummy
()
for
msg
in
pofile
:
for
msg
in
pofile
:
converter
.
convert_msg
(
msg
)
converter
.
convert_msg
(
msg
)
...
@@ -175,7 +179,7 @@ def make_dummy(file, locale):
...
@@ -175,7 +179,7 @@ def make_dummy(file, locale):
# do something reasonable.
# do something reasonable.
pofile
.
metadata
[
'Plural-Forms'
]
=
'nplurals=2; plural=(n != 1);'
pofile
.
metadata
[
'Plural-Forms'
]
=
'nplurals=2; plural=(n != 1);'
new_file
=
new_filename
(
file
,
locale
)
new_file
=
new_filename
(
file
name
,
locale
)
create_dir_if_necessary
(
new_file
)
create_dir_if_necessary
(
new_file
)
pofile
.
save
(
new_file
)
pofile
.
save
(
new_file
)
...
@@ -191,12 +195,12 @@ def main():
...
@@ -191,12 +195,12 @@ def main():
"""
"""
Generate dummy strings for all source po files.
Generate dummy strings for all source po files.
"""
"""
LOCALE
=
CONFIGURATION
.
dummy_locale
SOURCE_MSGS_DIR
=
CONFIGURATION
.
source_messages_dir
SOURCE_MSGS_DIR
=
CONFIGURATION
.
source_messages_dir
print
"Processing source language files into dummy strings:"
for
locale
,
converter
in
zip
(
CONFIGURATION
.
dummy_locales
,
[
Dummy
(),
Dummy2
()]):
print
"Processing source language files into dummy strings, locale {}:"
.
format
(
locale
)
for
source_file
in
CONFIGURATION
.
source_messages_dir
.
walkfiles
(
'*.po'
):
for
source_file
in
CONFIGURATION
.
source_messages_dir
.
walkfiles
(
'*.po'
):
print
' '
,
source_file
.
relpath
()
print
' '
,
source_file
.
relpath
()
make_dummy
(
SOURCE_MSGS_DIR
.
joinpath
(
source_file
),
LOCALE
)
make_dummy
(
SOURCE_MSGS_DIR
.
joinpath
(
source_file
),
locale
,
converter
)
print
print
...
...
i18n/generate.py
View file @
ece123e9
...
@@ -115,7 +115,8 @@ def main(argv=None):
...
@@ -115,7 +115,8 @@ def main(argv=None):
for
locale
in
CONFIGURATION
.
translated_locales
:
for
locale
in
CONFIGURATION
.
translated_locales
:
merge_files
(
locale
,
fail_if_missing
=
args
.
strict
)
merge_files
(
locale
,
fail_if_missing
=
args
.
strict
)
# Dummy text is not required. Don't raise exception if files are missing.
# Dummy text is not required. Don't raise exception if files are missing.
merge_files
(
CONFIGURATION
.
dummy_locale
,
fail_if_missing
=
False
)
for
locale
in
CONFIGURATION
.
dummy_locales
:
merge_files
(
locale
,
fail_if_missing
=
False
)
compile_cmd
=
'django-admin.py compilemessages'
compile_cmd
=
'django-admin.py compilemessages'
execute
(
compile_cmd
,
working_directory
=
BASE_DIR
)
execute
(
compile_cmd
,
working_directory
=
BASE_DIR
)
...
...
i18n/tests/test_config.py
View file @
ece123e9
...
@@ -29,5 +29,5 @@ class TestConfiguration(TestCase):
...
@@ -29,5 +29,5 @@ class TestConfiguration(TestCase):
self
.
assertIsNotNone
(
locales
)
self
.
assertIsNotNone
(
locales
)
self
.
assertIsInstance
(
locales
,
list
)
self
.
assertIsInstance
(
locales
,
list
)
self
.
assertIn
(
'en'
,
locales
)
self
.
assertIn
(
'en'
,
locales
)
self
.
assertEqual
(
'eo'
,
CONFIGURATION
.
dummy_locale
)
self
.
assertEqual
(
'eo'
,
CONFIGURATION
.
dummy_locale
s
[
0
]
)
self
.
assertEqual
(
'en'
,
CONFIGURATION
.
source_locale
)
self
.
assertEqual
(
'en'
,
CONFIGURATION
.
source_locale
)
i18n/tests/test_dummy.py
View file @
ece123e9
...
@@ -33,13 +33,13 @@ class TestDummy(TestCase):
...
@@ -33,13 +33,13 @@ class TestDummy(TestCase):
@ddt.data
(
@ddt.data
(
(
u"hello my name is Bond, James Bond"
,
(
u"hello my name is Bond, James Bond"
,
u"héll
ø mý nämé ïs Bønd, Jämés Bø
nd Ⱡ'σяєм ι#"
),
u"héll
ö mý nämé ïs Bönd, Jämés Bö
nd Ⱡ'σяєм ι#"
),
(
u"don't convert <a href='href'>tag ids</a>"
,
(
u"don't convert <a href='href'>tag ids</a>"
,
u"d
øn't çønvért <a href='href'>täg ïds</a> Ⱡ'σяєм ιρѕυ
#"
),
u"d
ön't çönvért <a href='href'>täg ïds</a> Ⱡ'σяєм
#"
),
(
u"don't convert
%(name)
s tags on
%(date)
s"
,
(
u"don't convert
%(name)
s tags on
%(date)
s"
,
u"d
øn't çønvért
%(name)
s tägs øn
%(date)
s Ⱡ'σяєм ιρѕ
#"
),
u"d
ön't çönvért
%(name)
s tägs ön
%(date)
s Ⱡ'σяєм
#"
),
)
)
def
test_dummy
(
self
,
data
):
def
test_dummy
(
self
,
data
):
"""
"""
...
@@ -53,7 +53,7 @@ class TestDummy(TestCase):
...
@@ -53,7 +53,7 @@ class TestDummy(TestCase):
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"À l
øvélý däý før ä çüp ø
f téä. Ⱡ'σяєм #"
expected
=
u"À l
övélý däý för ä çüp ö
f téä. Ⱡ'σяєм #"
self
.
converter
.
convert_msg
(
entry
)
self
.
converter
.
convert_msg
(
entry
)
self
.
assertUnicodeEquals
(
entry
.
msgstr
,
expected
)
self
.
assertUnicodeEquals
(
entry
.
msgstr
,
expected
)
...
@@ -61,8 +61,8 @@ class TestDummy(TestCase):
...
@@ -61,8 +61,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"À l
øvélý däý før ä çüp ø
f téä. Ⱡ'σяєм #"
expected_s
=
u"À l
övélý däý för ä çüp ö
f téä. Ⱡ'σяєм #"
expected_p
=
u"À l
øvélý däý før sømé çüps ø
f téä. Ⱡ'σяєм ιρ#"
expected_p
=
u"À l
övélý däý för sömé çüps ö
f téä. Ⱡ'σяєм ιρ#"
self
.
converter
.
convert_msg
(
entry
)
self
.
converter
.
convert_msg
(
entry
)
result
=
entry
.
msgstr_plural
result
=
entry
.
msgstr_plural
self
.
assertUnicodeEquals
(
result
[
'0'
],
expected_s
)
self
.
assertUnicodeEquals
(
result
[
'0'
],
expected_s
)
...
...
lms/envs/common.py
View file @
ece123e9
...
@@ -498,7 +498,8 @@ LANGUAGE_CODE = 'en' # http://www.i18nguy.com/unicode/language-identifiers.html
...
@@ -498,7 +498,8 @@ LANGUAGE_CODE = 'en' # http://www.i18nguy.com/unicode/language-identifiers.html
# Sourced from http://www.localeplanet.com/icu/ and wikipedia
# Sourced from http://www.localeplanet.com/icu/ and wikipedia
LANGUAGES
=
(
LANGUAGES
=
(
(
'eo'
,
u'Dummy Language (Esperanto)'
),
# Dummy languaged used for testing
(
'eo'
,
u'Dummy Language (Esperanto)'
),
# Dummy language used for testing
(
'fake2'
,
u'Fake translations'
),
# Another dummy language for testing (not pushed to prod)
(
'ach'
,
u'Acholi'
),
# Acoli
(
'ach'
,
u'Acholi'
),
# Acoli
(
'ar'
,
u'العربية'
),
# Arabic
(
'ar'
,
u'العربية'
),
# Arabic
...
...
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