Translating » History » Version 66
Dominic Cleal, 04/27/2016 10:05 AM
remove reference to copying Rails translations, use rails-i18n
1 | 6 | Lukas Zapletal | h1. Translating for contributors |
---|---|---|---|
2 | 1 | Lukas Zapletal | |
3 | 7 | Lukas Zapletal | h2. General tips |
4 | |||
5 | It is important not to change punctuation and whitespace. For example if the English string is "blah." it must be translated as "xyz." with the dot at the end. The same for an extra space - e.g. "blah " must be "xyz ". Although we try to eliminate all the extra spaces, there are rare cases where we need them. There is a checker (pofilter) which is executed regularly by developers to catch and fix all these types of mistakes. |
||
6 | |||
7 | 32 | Dominic Cleal | There are model names in the translation strings, you can get the full list here: https://github.com/theforeman/foreman/blob/develop/locale/model_attributes.rb |
8 | 7 | Lukas Zapletal | |
9 | These model names are in two formats: "Model name" (name of the database table) and "Modelname|Column name" for column name. Here are few examples how to translate them: |
||
10 | |||
11 | _('Compute resource') -> "Compute Resource" |
||
12 | |||
13 | _('ComputeResource|Description') -> "Description" |
||
14 | |||
15 | Several models have prefixes in the form something/ or Something:: - you can ignore these. Example: |
||
16 | |||
17 | _('Audited/adapters/active record/audit') -> "Audit" |
||
18 | |||
19 | _('Audited::Adapters::ActiveRecord::Audit|Associated name') -> "Associated Name" |
||
20 | |||
21 | 6 | Lukas Zapletal | h2. Using Transifex |
22 | |||
23 | Go to https://www.transifex.com/projects/p/foreman and register/login. Then you can use the Transifex interface to do all translations. The project on Transifex automatically updates when we add new strings into git. Foreman team regularly downloads new translations to the develop branch in git as well, therefore there is no action needed when you finish with translations. It will be pulled eventually (e.g. before the next release). |
||
24 | |||
25 | Read the tips bellow if you want to start translating now. |
||
26 | 1 | Lukas Zapletal | |
27 | 2 | Lukas Zapletal | h2. Manually |
28 | |||
29 | If you prefer, you can edit PO files directly using your preferred editor. Please make sure the encoding of the files is UTF-8. It is also recommended to test your translations before submitting a Pull Request on the github using either: |
||
30 | |||
31 | 28 | Lukas Zapletal | foreman# rake locale:pack |
32 | 1 | Lukas Zapletal | |
33 | 2 | Lukas Zapletal | or |
34 | 1 | Lukas Zapletal | |
35 | 7 | Lukas Zapletal | foreman# make -C locale check all-mo |
36 | 2 | Lukas Zapletal | |
37 | 29 | Lukas Zapletal | Note that locale:pack is an alias for gettext:pack which is only avaiable in the development environment. |
38 | |||
39 | 1 | Lukas Zapletal | The above command should not print any error message. Also you should start Foreman UI and see if your translations do fit (sometimes longer strings can wrap or even break the UI). If you start Foreman in the production mode, you need to do one of the above commands every time you change your translation. In the development mode, you only need to restart Foreman to see the changes. |
40 | |||
41 | 56 | Benjamin Papillon | Note: For CentOS/RHEL6 systems, you need the following packages : |
42 | |||
43 | gettext make |
||
44 | |||
45 | 1 | Lukas Zapletal | More info about contributing your translation directly is on our [[Contribute]] wiki page. |
46 | |||
47 | 33 | Lukas Zapletal | h2. Changing language |
48 | |||
49 | To change your language, to to User account page and change our language from Browser default to your preferred one. (This is work in progress) |
||
50 | |||
51 | To quickly change language without going to user settings add ?locale=XX to any Foreman URL. For example visit: |
||
52 | |||
53 | http://localhost:3000/?locale=de |
||
54 | |||
55 | 39 | Lukas Zapletal | and Foreman will remember the language setting for the whole session. Note: The current user needs to have "Browser Locale" set in the account settings, otherwise this will not work. |
56 | 33 | Lukas Zapletal | |
57 | 6 | Lukas Zapletal | h1. Translating for developers |
58 | 1 | Lukas Zapletal | |
59 | 15 | Lukas Zapletal | h2. Extracting strings |
60 | |||
61 | There are several rules to follow when marking strings for translations with _("") and similar functions: |
||
62 | |||
63 | 30 | Dominic Cleal | * To translate a string use @_("My string")@ |
64 | 45 | Lukas Zapletal | * To translate string with a parameter use @_("String with param: %s") % param@ |
65 | * To translate string with more than one parameters do not use @_("Params: %s and %s") % [param1, param2]@ which is translator-unfriendly |
||
66 | * Therefore for more than one parameters use @_("Params: %{a} and %{b}") % {:a => foo, :b => bar}@ |
||
67 | 62 | Tomer Brisker | * Note that parameters are not translated. Variables should not contain text that needs translation. |
68 | 30 | Dominic Cleal | * To mark something for translation (but not translate) use @N_("String")@ |
69 | * To use plural form use @n_("One", "Two", number)@ - note this function always accepts three parameters as the base language is usually English but translators are able to define as many plural forms as they need. |
||
70 | 45 | Lukas Zapletal | * Plural forms are usually used with one parameter, do not forget to add trailing parameter to it: @n_("%s minute", "%s minutes", @param) % @param@ |
71 | 47 | Lukas Zapletal | * When using strings with ERB (e.g. for deface gem), escape properly: n_('Test <%%= %{var1} %%>') % { :var1 => "xxx" } |
72 | * Note that gettext does not extract from interpolation - this will not work: "blah #{_('key')} blah" |
||
73 | 30 | Dominic Cleal | |
74 | h3. Models and columns |
||
75 | |||
76 | * To render name from model use @s_("Modelname|Fieldname")@ - check @./locale/model_attributes.rb@ for all models/fields which are accepted. |
||
77 | * All our form helpers have been enriched and understand model and column names - if the field is in the model_attribute.rb (above), it does not need to be translated explicitly (e.g. text_f f, :name is enough and will be translated to "Modelname|Name") |
||
78 | |||
79 | 59 | Lukas Zapletal | h3. Exceptions |
80 | |||
81 | We have defined two exceptions `Foreman::Exception` and `Foreman::WrappedException`. Both are generic exceptions which are i18n-friendly. Use the following style to properly format messages: |
||
82 | |||
83 | <pre> |
||
84 | raise ::Foreman::Exception.new(N_("Localized error message")) |
||
85 | raise ::Foreman::Exception.new(N_("Localized error message: %s", substring_message)) |
||
86 | raise ::Foreman::Exception.new(N_("Localized error message %{a} and %{b}", {:a => a, :b => b})) |
||
87 | 63 | Daniel Lobato Garcia | raise ::Foreman::WrappedException.new(wrapped_exception, N_("Localized error message")) |
88 | 59 | Lukas Zapletal | </pre> |
89 | |||
90 | It is _very_ important to use `N_` and not the simple `_` (underscore) function and to avoid using Ruby string interpolation, because those exceptions prints out error code which are generated from exception class names and main (untranslated) messages. There is also a rake task that goes through our codebase and generates list of all possible error codes which we keep on the wiki page [[ErrorCodes]]. |
||
91 | |||
92 | 60 | Lukas Zapletal | If an exception is needed to be untranslated, it can be used without underscore functions. Beware, that parameters can be also passed, but Ruby only support hash interpolation: |
93 | |||
94 | <pre> |
||
95 | raise ::Foreman::Exception.new("This works fine") |
||
96 | raise ::Foreman::Exception.new("This works fine %{foo}", {:foo => "too"}) |
||
97 | raise ::Foreman::Exception.new("But this %{s} will not work", 'example') |
||
98 | </pre> |
||
99 | |||
100 | 30 | Dominic Cleal | h3. Helping translators |
101 | |||
102 | 1 | Lukas Zapletal | * Do not break strings with newlines because then the strings have many whitespace and it looks confusing for translators like "blah \\n blah". If you must separate string on several lines, you can use HEREDOC or you can contatenate strings like "line1" + "line2" because Ruby Gettext detects them both. |
103 | 30 | Dominic Cleal | * If you want to leave a note to the translator, just drop a comment before the string in the format of @# TRANSLATORS: your comment here@ |
104 | 1 | Lukas Zapletal | * Note that all HEREDOC strings are automatically extracted, when adding API documentation descriptions via HEREDOC, leave a message to translators not to translate these (API documentation will not be translated at the moment). |
105 | 30 | Dominic Cleal | |
106 | 31 | Dominic Cleal | h3. JavaScript |
107 | |||
108 | 58 | Walden Raines | * Both @__@ and @n__@ functions are available and work in much the same way as in Ruby, with the following exceptions.. |
109 | * Interpolation of values uses @Jed.sprintf@ on the translated string, so for a single parameter: @Jed.sprintf(__("Foo: %s"), "bar")@ |
||
110 | * Multiple parameters must be named: @Jed.sprintf(__("Example: %(foo) %(bar)"), {foo: "a", bar: "b"})@ |
||
111 | 31 | Dominic Cleal | |
112 | 30 | Dominic Cleal | h3. Storing strings |
113 | |||
114 | 25 | Lukas Zapletal | * Strings get extracted into ./locale/foreman.pot file, model and column names are in ./locale/model_attributes.rb |
115 | 66 | Dominic Cleal | * Additional Rails strings are provided by the rails-i18n gem |
116 | 31 | Dominic Cleal | * PO files are converted into JSON objects to be consumed by Jed, stored at @./app/assets/javascripts/locale/$LANG/app.js@ |
117 | 15 | Lukas Zapletal | * For more info go here: http://www.yotabanana.com/hiki/ruby-gettext-howto.html |
118 | |||
119 | From time to time it is good to extract strings and update translations with incoming strings, so translators are able to work on them. We usually do this before releases, but it is good idea to do this on a weekly/monthly basis. For string extractions, please *do not* use rake gettext:find but use |
||
120 | |||
121 | foreman# rake locale:find |
||
122 | |||
123 | 21 | Lukas Zapletal | because it also extracts model names and columns and filters them plus it adds some notes to translators (see locale:find_model rake task). Although locale:find does some checks for malformed strings, it is good idea to run additional pofilter check which is able to find many mistakes like trailing whitespace and others: |
124 | |||
125 | foreman# make -C locale check -j4 |
||
126 | foreman# make -C locale clean |
||
127 | 15 | Lukas Zapletal | |
128 | h2. Generating gettext translate tables |
||
129 | |||
130 | For production environment, you need to compile PO files into binary translate tables (MO files). This is *not needed* for development or test environments as in these modes Foreman reads PO files directly. |
||
131 | |||
132 | To generate gettext MO files, you can do either |
||
133 | |||
134 | foreman# rake gettext:pack |
||
135 | |||
136 | or |
||
137 | |||
138 | foreman# make -C locale |
||
139 | |||
140 | Both tools generate the same result, the latter is a bit faster and allows additional checks (see locale/Makefile targets). If you install from distribution packages, you do not need to run this because everything has been pre-compiled already. |
||
141 | |||
142 | 8 | Lukas Zapletal | h2. Adding new language |
143 | 6 | Lukas Zapletal | |
144 | 2 | Lukas Zapletal | Adding new language into Foreman is easy. You need to take two steps - first of all create new gettext PO file as a copy from POT and edit the header (at least set plural configuration): |
145 | 12 | Lukas Zapletal | |
146 | 3 | Lukas Zapletal | # cp locale/foreman.pot locale/xx/foreman.po |
147 | 6 | Lukas Zapletal | # vim locale/xx/foreman.po |
148 | 12 | Lukas Zapletal | |
149 | 66 | Dominic Cleal | And add the language to Transifex using their web interface. |
150 | 2 | Lukas Zapletal | |
151 | 6 | Lukas Zapletal | h2. How to pull translations |
152 | 1 | Lukas Zapletal | |
153 | 4 | Lukas Zapletal | To get updated translations from Transifex you will need account there (https://www.transifex.com) and the tx cli tool. |
154 | |||
155 | On Fedora: |
||
156 | |||
157 | 51 | Lukas Zapletal | # yum -y install transifex-client gettext make intltool |
158 | 4 | Lukas Zapletal | |
159 | On Debian: |
||
160 | |||
161 | 51 | Lukas Zapletal | # apt-get install transifex-client gettext make intltool-debian |
162 | 4 | Lukas Zapletal | |
163 | Then configure your account: |
||
164 | |||
165 | 51 | Lukas Zapletal | $ cat ~/.transifexrc |
166 | [https://www.transifex.com] |
||
167 | hostname = https://www.transifex.com |
||
168 | username = <your_username> |
||
169 | password = <your_password> |
||
170 | token = |
||
171 | 4 | Lukas Zapletal | |
172 | 48 | Lukas Zapletal | Note that token is empty, should not be set. Then prepare new topic branch (because the following command will make new commits to your git repo): |
173 | 1 | Lukas Zapletal | |
174 | 51 | Lukas Zapletal | git checkout -b update-translations |
175 | 4 | Lukas Zapletal | |
176 | 48 | Lukas Zapletal | Before you start check if there are new languages on the Transifex site that are worth adding into Foreman (are close to 100 %). You need to download all po files manually and create the proper directory structure. Make sure the PO file header is correct, specifically plural settings and when necessary edit .tx/config file to add a mapping there. |
177 | 43 | Dominic Cleal | |
178 | 55 | Dominic Cleal | Now you can update translations from Transiflex and Rails i18n upstream, regenerate the JavaScript locale files, extract new strings (but throw away PO files merge - we do not need that when using Transifex.com): |
179 | 48 | Lukas Zapletal | |
180 | 51 | Lukas Zapletal | make -C locale tx-update |
181 | 53 | Lukas Zapletal | |
182 | 54 | Lukas Zapletal | Note: run this command in the Foreman git root directory. |
183 | 4 | Lukas Zapletal | |
184 | 49 | Lukas Zapletal | Check git log, you should have few new commits stacked, all with i18n prefix. Then you can push changes. |
185 | 4 | Lukas Zapletal | |
186 | 51 | Lukas Zapletal | git push |
187 | 9 | Lukas Zapletal | |
188 | 57 | Lukas Zapletal | h2. Not extracted |
189 | 9 | Lukas Zapletal | |
190 | 57 | Lukas Zapletal | Some parts are (yet) not extracted for translation. These include: |
191 | 9 | Lukas Zapletal | |
192 | 19 | Dominic Cleal | * "Clear" tooltip in scoped_search |
193 | 1 | Lukas Zapletal | * any external assert gems, e.g. SPICE HTML 5 console, noVNC? |
194 | 20 | Dominic Cleal | * column names used in scoped_search |
195 | 61 | Dominic Cleal | |
196 | A number of other items are "filed as bugs":http://projects.theforeman.org/projects/foreman/issues?utf8=%E2%9C%93&set_filter=1&f[]=status_id&op[status_id]=o&f[]=category_id&op[category_id]=%3D&v[category_id][]=57&f[]=&c[]=tracker&c[]=status&c[]=priority&c[]=subject&c[]=author&c[]=assigned_to&c[]=updated_on&c[]=category&c[]=fixed_version&c[]=position&group_by=. |
||
197 | 57 | Lukas Zapletal | |
198 | Things that perhaps does not need to be translated: |
||
199 | 41 | Dominic Cleal | * rake tasks |
200 | * logs? |
||
201 | 35 | Dominic Cleal | |
202 | Some parts live in external libraries or vendored assets: |
||
203 | 36 | Dominic Cleal | |
204 | 35 | Dominic Cleal | * will_paginate (Dom working on this) |
205 | ** @page_entries_info .. :model@ has unextracted strings in places, but we can't change this easily without fixing will_paginate |
||
206 | * jquery.dataTables (this has its own localisation method) |
||
207 | 10 | Lukas Zapletal | * Puppet log messages, log levels |
208 | * noVNC, spice-html5 |