1# Translating mypaint
2
3[![Translation status](https://hosted.weblate.org/widgets/mypaint/-/svg-badge.svg)](https://hosted.weblate.org/engage/mypaint/?utm_source=widget)
4
5MyPaint uses WebLate for its translations.
6You can get involved at <https://hosted.weblate.org/engage/mypaint/>.
7
8That might be all the information you need
9if you just want to help ensure that MyPaint
10is correctly translated into your language.
11
12# Information for coders and maintainers
13
14We use [GNU gettext][gettext] for runtime translation of program text.
15
16Please note that there are two projects that need translating for the
17MyPaint app:
18
19* libmypaint, the brush engine library that MyPaint uses.
20* MyPaint itself.
21
22both projects are exposed on WebLate.
23
24The rest of this document covers translating
25the MyPaint application itself, minus libmypaint.
26
27## Making strings translatable
28
29This section gives an overview of how to make strings translatable
30in the source code. For in-depth technical details of the workings,
31of gettext, refer to [its manual][gettext].
32
33Strings that need to be translatable have to be used as arguments in calls
34to particular translation functions, also referred to as "macros"
35(preprocessor macros is a standard way of using gettext in C, the python calls
36used are not actually macros, but rather functions or function aliases).
37The purpose of these calls are twofold: they make it possible to extract the
38translatable strings and related information from the source code _and_ they
39perform the actual translation lookups at runtime.
40
41> **Don't use aliases of the translation functions!**
42> Even though the _lookup_ will still work, the _extraction_
43> process is based on keywords, and cannot deduce aliasing, resulting
44> in the strings not being extracted to the translation template.
45
46### Basic translation: `_(message)`
47
48The `_` function is an alias of the standard gettext function, and takes
49the string _literal_ of the message to be translated as its only argument.
50If there is a comment block immediately preceding the **first line**
51of the _argument_, that comment will be extracted as well to provide
52information about the string to translators.
53
54When extracted, the argument string will appear as a msgid field in the translation
55files, in conjunction with a set of extracted comments and source code locations.
56
57Most of the time the `C_` function should be favored over `_`, when creating new strings,
58but be careful about replacing existing `_(...)` calls with `C_(...)`.
59See the following sections for details.
60
61### Context-specific translation: `C_(context, message)`
62
63The `C_` "macro" takes a context string literal in addition to the message
64string literal. The context has two purposes: it can provide useful
65information to the translators about how the string is used and it makes
66it _possible_ to have different translations for the same message string
67(when an identical message literal is used in different places).
68
69For more information, see [the relevant section in the gettext manual][gettext_ctx]
70
71Be careful about changing existing calls to `_` with calls to `C_`
72just to add contextual information when there is no need for disambiguation.
73The reason is that such changes will mark existing translations of that message
74as fuzzy - and such translations will not be used until the fuzzy flag has been
75removed (usually by a translator reviewing changes).
76If you just want to add documentation, use a translator comment.
77
78### Adding translator comments
79
80An important thing to know about _translator comments_ is that they are only
81extracted when preceding the line that the string literal of the _message_
82**starts on**. See the examples below for how comment placement matters.
83
84<details>
85<summary>Examples</summary>
86
87```
88# This comment will be extracted
89translated = _("my message")
90
91# This comment will be extracted too
92translated = C_("context of my message", "my message")
93
94# Both of these comment lines will
95# be extracted; they form a block.
96translated = C_("context of my message", "my message")
97
98# This comment will NOT be extracted!
99translated = _(
100    "this message is really long, and has been placed on its very own line"
101)
102
103translated = _(
104    # But this comment WILL be extracted
105    "this message is really long, and has been placed on its very own line"
106)
107
108translated = C_(
109    # This comment precedes the CONTEXT line and will NOT be extracted!
110    "context of my message",
111    "my message"
112)
113
114translated = C_(
115    "context of my message",
116    # This comment precedes the MESSAGE line and WILL be extracted
117    "my message"
118)
119
120```
121</details>
122
123### Using variables in message strings
124
125When the translated strings contain variables, use python brace format:
126```
127translated = C_(
128    "shmoo-counter: status message",
129	# TRANSLATORS: We have to use pounds for reasons of historical accuracy
130	"Counted {num_shmoos} shmoos, weighing a total of {total_weight} pounds."
131	).format(num_shmoos=len(shmoos), total_weight=sum([s.weight for s in shmoos]))
132```
133
134_Never_ stitch together translated fragments with variables - it will always
135make translation very difficult. For many languages doing it  may even make it
136impossible to produce translations with correct grammar, due to the order of
137arguments being impossible to change.
138
139## After updating program strings
140
141After adding or changing any string in the source text which
142makes use of the gettext macros, you will need to manually run
143
144    cd po/
145    ./update_potfiles.sh
146
147    ./update_languages.sh
148
149and then commit the modified `po/mypaint.pot` & `po/*.po` too,
150along with your changes.
151
152The `.pot` file alone can be updated by running
153just the first command,
154if all you want to do is compare diffs.
155
156The `update_metadata.sh` script does not need to be run on a regular basis.
157It is just a convenience for generating generic headers for new language files
158and for updating the version field of existing language files.
159
160# Information for translators
161
162## New translation (manual)
163
164Start by putting a new stub `.po` file into this directory.
165
166To make such a file you can
167copy the header from an existing `.po` file
168and modify it accordingly.
169
170Unless there are several country-specific dialects for your language,
171the file should be named simply `ll.po`
172where "ll" is a recognized [language code][ll].
173
174If there are several dialects for your language,
175the file should be named `ll_CC.po`
176where "CC" is the [country code][CC].
177
178Before you can work on it,
179you will need to update the `.po` file
180from the most recent `.pot` template file
181generated by the developers.
182
183## Update translation (manual)
184
185Before working on a translation,
186update the `po` file for your language.
187For example, for the French translation, run:
188
189    update_languages.sh fr.po
190
191## Use/Test the translation
192
193After modifying the translation,
194you can run MyPaint in demo mode to see the changes:
195
196    python setup.py demo
197
198If you want to run MyPaint with a specific translation on Linux,
199here are two ways of doing so:
200
201You can either use the LANG environment variable
202like this (the locale needs to be supported):
203
204	LANG=ll_CC.utf8 python setup.py demo
205
206where "ll" is a [language code][ll], and and "CC" is a [country code][CC].
207
208If you don't have to locale of the language you want
209to test installed, you can use the LANGUAGE variable
210instead:
211
212	LANGUAGE=ll_CC python setup.py demo
213
214> You don't have to supply the country code (CC) if you
215> don't need to disambiguate multiple dialects.
216
217> When using `LANGUAGE` without having the locale installed,
218> some strings that are not part of MyPaint will not be translated.
219> For example, button strings in file chooser dialogs.
220
221To run MyPaint with the original strings, for comparison,
222you can use the `LC_MESSAGES` variable like this:
223
224    LC_MESSAGES=C python setup.py demo
225
226## Send changes (manual)
227
228Before you send your changes, please make sure that
229your changes are based on the
230current development (git) version of MyPaint.
231
232We prefer changes as [Github pull requests][PR],
233but if you do not know git you can also [open a new issue on github][NEW_ISSUE]
234and attach either a unified diff or the new/updated .po file to it.
235
236## Weblate
237
238Weblate provides a browser-based interface for adding, editing
239and updating translations. It's a very good way to provide
240translations without having to worry about the technical details.
241
242If you are interested in keeping the translations up to date,
243please subscribe to the MyPaint project on WebLate:
244<https://hosted.weblate.org/accounts/profile/#subscriptions>.
245
246-------------------
247
248[gettext]: http://www.gnu.org/software/hello/manual/gettext/ (Official GNU gettext manual)
249[gettext_ctx]: https://www.gnu.org/software/gettext/manual/gettext.html#Contexts (gettext manual section on message contexts)
250[ll]: http://www.gnu.org/software/hello/manual/gettext/Usual-Language-Codes.html#Usual-Language-Codes ("ll" options)
251[CC]: http://www.gnu.org/software/hello/manual/gettext/Country-Codes.html#Country-Codes ("CC" options)
252[PR]: https://help.github.com/articles/using-pull-requests/
253[NEW_ISSUE]: https://github.com/mypaint/mypaint/issues/new?title=Manual+translations+for:+LANGUAGE&body=New%2Fupdated+translations+for+%2E%2E%2E
254