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
b8a8575d
Commit
b8a8575d
authored
Jan 17, 2014
by
Ned Batchelder
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Further edits
parent
8c79f13d
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
87 additions
and
60 deletions
+87
-60
docs/en_us/developers/source/i18n.rst
+87
-60
No files found.
docs/en_us/developers/source/i18n.rst
View file @
b8a8575d
...
...
@@ -27,15 +27,17 @@ unfortunately limits what you can do with strings in the code. In general:
runtime, there is no way for the translator to construct a proper sentence
in their language.
2. Do
not join together strings
at runtime to create sentences.
2. Do
n't join strings together
at runtime to create sentences.
3. Limit the amount of text in strings that is not presented to the user. HTML
markup is better applied after the translation. If you give HTML to the
translators, there's a good chance they will translate your tags or
attributes.
See the detailed :ref:`Style Guidelines <style_guidelines>` at the end for
details.
4. Use placeholders with descriptive names: ``"Welcome {student_name}"`` is
much better than ``"Welcome {0}"``.
See the detailed Style Guidelines at the end for details.
Editing source files
...
...
@@ -77,14 +79,19 @@ XModules, Inputtypes and Responsetypes forbid importing Django. Each of these
has its own way of accessing translations. You'll use lines like these
instead::
# for XBlock & XModule:
#
##
for XBlock & XModule:
_ = self.runtime.service(self, "i18n").ugettext
# Translators: a greeting to newly-registered students.
message = _("Welcome!")
# for InputType and ResponseType:
_ = self.capa_system.i18n.ugettext
# Translators: a greeting to newly-registered students.
message = _("Welcome!")
"Translators" comments will work in these places too, so don't be shy about
providing clarifying comments to the translators.
Django template files
=====================
...
...
@@ -105,7 +112,7 @@ Mako template files
In Mako template files (`templates/*.html`), you can use all of the tools
available to python programmers. Just make sure to import the relevant
functions first. Here's a
m
ako template example::
functions first. Here's a
M
ako template example::
<%! from django.utils.translation import ugettext as _ %>
...
...
@@ -172,11 +179,11 @@ Other kinds of code
We have not yet established guidelines for internationalizing the following.
*
c
ourse content (such as subtitles for videos)
*
C
ourse content (such as subtitles for videos)
*
d
ocumentation (written for Sphinx as .rst files)
*
D
ocumentation (written for Sphinx as .rst files)
*
c
lient-side templates written using Underscore.
*
C
lient-side templates written using Underscore.
Building and testing your code
...
...
@@ -186,32 +193,16 @@ These instructions assume you are a developer writing new code to check in to
Github. For other use cases in the translation life cycle (such as translating
the strings, or checking the translations into Github, see use cases).
1. Run the rake i18n:extract command to create human-readable .po files. This
command may take a minute or two to complete:
::
1. Create human-readable .po files with the latest strings. This command may
take a minute or two to complete::
$ cd edx-platform
$ rake assets
$ rake i18n:extract
2. Generate dummy strings: run rake i18n:dummy to create fake translations. See
coverage testing (below) for more details.
a. By default, these are created in the Esperanto language directory.
1. This will blow away any actual Esperanto translation files that may be
there. You can revert to the Github head after you complete testing.
2. You will need to switch your browser to Esperanto in order to view
the dummy text.
3. Django's implementation requires us to use a real language (like
Esperanto..) rather than an invented language (like Esperanto..
er Martian) for this testing.
b. Do not check the dummy text in to Github (in conf/locale/eo/LC_MESSAGES).
::
2. Generate dummy strings: See coverage testing (below) for more details. This
will create an "Esperanto" translation that is actually over-accented
English. Use this to create fake translations::
$ rake i18n:dummy
...
...
@@ -219,26 +210,26 @@ the strings, or checking the translations into Github, see use cases).
$ rake i18n:generate
4. Django should be ready to go. The next time you run
studio or lms
with a
non-English browser, the non-English strings (from step 3, above) should be
displayed. (But be sure that your settings for USE_I18N and USE_L10N are
both set to True. USE_I18N is currently set to False by default in
common.py, but is set to True in lms/envs/dev.py and cms/envs/dev.py)
4. Django should be ready to go. The next time you run
Studio or LMS
with a
browser set to Esperanto, the accented-English strings (from step 3, above)
should be displayed. Be sure that your settings for ``USE_I18N`` and
``USE_L10N`` are both set to True. ``USE_I18N`` is set to False by default
in common.py, but is set to True in development settings files.
5. With your browser set to Esperanto, review the pages affected by your code
and verify that you see fake translations. If you see plain English instead,
your code is not being properly translated. Review the steps in editing
source files (above)
source files (above)
.
Coverage testing
****************
This tool is used during the bootstrap phase, when presumably (1) there is a
lot of
E
dX source code to be converted, and (2) there are not a lot of
available translations for externalized
E
dX strings. At the end of the
lot of
e
dX source code to be converted, and (2) there are not a lot of
available translations for externalized
e
dX strings. At the end of the
bootstrap phase, we will eventually deprecate this tool in favor of other
processes. Once most of the
E
dX source code has been successfully converted,
processes. Once most of the
e
dX source code has been successfully converted,
and there are several full translations available, it will be easier to detect
and correct specific gaps in compliance.
...
...
@@ -273,12 +264,11 @@ This dummy text is also distinguished by Lorem ipsum text at the end of each
string, and is always terminated with "#". The original English string is
padded by about 30% extra characters, to simulate some language (like German)
which tend to have longer strings than English. If you see problems with your
page layout, such as columns that do
not fit, or text that is truncated (the #
character should always be displayed on every string), then you will probably
need to fix the page layouts accordingly to accommodate the longer strings.
page layout, such as columns that do
n't fit, or text that is truncated (the
``#`` character should always be displayed on every string), then you will
probably need to fix the page layouts accordingly to accommodate the longer
strings.
.. _style_guidelines:
Style guidelines
****************
...
...
@@ -288,7 +278,7 @@ Don't append strings, interpolate values
It is harder for translators to provide reasonable translations of small
sentence fragments. If your code appends sentence fragments, even if it seems
to work
ok
for English, the same concatenation is very unlikely to work
to work
OK
for English, the same concatenation is very unlikely to work
properly for other languages.
Bad::
...
...
@@ -301,34 +291,36 @@ directory has." In some languages the fragments will be in different order. For
example, in Japanese, "files" will come before "has."
It is much easier for a translator to figure out how to translate the entire
sentence, using the pattern "The directory has
%d
files."
sentence, using the pattern "The directory has
{file_count}
files."
Good::
message = _("The directory has
%d files.") % len(
directory.files)
message = _("The directory has
{file_count} files.").format(file_count=
directory.files)
Use named
interpolation field
s
======================
========
Use named
placeholder
s
======================
Named fields are better, especially if there are multiple fields, or if some
fields will be locally formatted (for example, number, date, or currency).
Python string formatting provides both positional and named placeholders. Use
named placeholders, never use positional placeholders. Positional placeholders
can't be translated into other languages which may need to re-order them to
make syntactically correct sentences. Even with a single placeholder, a named
placeholder provides more context to the translator.
Bad::
message = _('Today is %s %d.') % (m, d)
Good
::
OK
::
message = _('Today is %(month)s %(day)s.') % {'month': m, 'day': d}
Be
tter
::
Be
st
::
message = _('Today is {month} {day}.').format(month=m, day=d)
Notice that in English, the month comes first, but in Spanish the day comes
first. This is reflected in the
edx-platform/conf/locale/es/LC_MESSAGES/django.po file like this::
first. This is reflected in the .po file like this::
# fragment from edx-platform/conf/locale/es/LC_MESSAGES/django.po
msgid "Today is {month} {day}."
...
...
@@ -390,6 +382,41 @@ The difference between the right way and the wrong way can be very subtle:
message = _("Goodbye.")
Be aware of nested syntax
=========================
When translating strings in templated files, you have to be careful of nested
syntax. For example, consider this Javascript fragment in a Mako template::
<script>
var feeling = '${_("I love you.")';
</script>
When rendered for a French speaker, it will produce this::
<script>
var feeling = 'Je t'aime.';
</script>
which is now invalid Javascript. This can be avoided by using double-quotes
for the Javascript string. The better solution is to use a filtering function
that properly escapes the string for Javascript use::
<script>
var feeling = '${escapejs(_("I love you."))}';
</script>
which produces::
<script>
var feeling = 'Je t\'aime.';
</script>
Other places that might be problematic are HTML attributes::
<img alt='${_("I love you.")}'>
Singular vs plural
==================
...
...
@@ -399,22 +426,22 @@ count::
if count == 1:
msg = _("There is 1 file.")
else:
msg = _("There are
%d files.") % count
msg = _("There are
{file_count} files.").format(file_count=count)
This is not the correct way to choose a string, because other languages have
different rules for when to use sing
lu
ar and when plural, and there may be more
different rules for when to use sing
ul
ar and when plural, and there may be more
than two choices!
One option is not to use different text for different counts::
msg = _("Number of files:
%d") % count
msg = _("Number of files:
{file_count}").format(file_count=count)
If you want to choose based on number, you need to use another gettext variant
to do it::
from django.utils.translation import ungettext
msg = ungettext("There is
%d file", "There are %d
files", count)
msg = msg
% count
msg = ungettext("There is
{file_count} file", "There are {file_count}
files", count)
msg = msg
.format(file_count=count)
This will properly use count to find a correct string in the translation file,
and then you can use that string to format in the count.
...
...
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