Left: | ||
Right: |
OLD | NEW |
---|---|
1 # CMS # | 1 # CMS # |
2 | 2 |
3 We use this CMS for [adblockplus.org](https://github.com/adblockplus/web.adblock plus.org/) | 3 We use this CMS for [adblockplus.org](https://github.com/adblockplus/web.adblock plus.org/) |
4 and related websites. It converts a directory with content data into static | 4 and related websites. It converts a directory with content data into static |
5 files. You are free to use it for other projects but please keep in mind that we | 5 files. You are free to use it for other projects but please keep in mind that we |
6 make no stability guarantees whatsoever and might change functionality any time. | 6 make no stability guarantees whatsoever and might change functionality any time. |
7 | 7 |
8 ## How to use ## | 8 ## Getting started ## |
ire
2017/12/04 10:17:13
This change is opinionated. I moved everything to
| |
9 | 9 |
10 ### Running the test server ### | 10 The easiest way to get started is to run a test server. The test server will |
11 | 11 convert your content directory on the fly, your changes will become visible |
12 The test server will convert your content directory on the fly, your changes | 12 immediately. To run it you need: |
13 will become visible immediately. To run it you need: | |
14 | 13 |
15 * Python 2.7 | 14 * Python 2.7 |
16 * [Jinja2](http://jinja.pocoo.org/) and | 15 * [Jinja2](http://jinja.pocoo.org/) and |
17 [Markdown](https://pypi.python.org/pypi/Markdown) modules (can be installed by | 16 [Markdown](https://pypi.python.org/pypi/Markdown) modules (can be installed by |
18 running `easy_install Jinja2 Markdown` from the command line) | 17 running `easy_install Jinja2 Markdown` from the command line) |
19 * A current copy of the | 18 * A current copy of the |
20 [cms repository](https://github.com/adblockplus/cms/) (can be | 19 [cms repository](https://github.com/adblockplus/cms/) (can be |
21 [downloaded as ZIP file](https://github.com/adblockplus/cms/archive/master.zip ) | 20 [downloaded as ZIP file](https://github.com/adblockplus/cms/archive/master.zip ) |
22 or cloned via `git clone https://github.com/adblockplus/cms.git`) | 21 or cloned via `git clone https://github.com/adblockplus/cms.git`) |
23 | 22 |
24 Optionally, the [Werkzeug](http://werkzeug.pocoo.org/) module can be installed | 23 Optionally, the [Werkzeug](http://werkzeug.pocoo.org/) module can be installed |
25 as well, this will provide some developer features. | 24 as well, this will provide some developer features. |
26 | 25 |
27 Run the `runserver.py` script from your content directory, e.g.: | 26 Run the `runserver.py` script from your content directory, e.g.: |
28 | 27 |
29 python ../cms/runserver.py | 28 python ../cms/runserver.py |
30 | 29 |
31 Alternatively, the content directory could also be specified as command line | 30 Alternatively, the content directory could also be specified as command line |
32 parameter of `runserver.py`. This will start a local web server on port 5000, | 31 parameter of `runserver.py`. This will start a local web server on port 5000, |
33 e.g. the page the page `pages/example.md` will be accessible under | 32 e.g. the page the page `pages/example.md` will be accessible under |
34 `http://localhost:5000/en/example`. | 33 `http://localhost:5000/en/example`. |
35 | 34 |
36 Note that the test server is inefficient and shouldn't be run in production. | 35 Note that the test server is inefficient and shouldn't be run in production. |
37 There you should generate static files as explained below. | 36 There you should generate static files as explained below. |
38 | 37 |
39 ### Generating the standalone test server ### | 38 ## Documentation ## |
40 | 39 |
41 The standalone test server is a single binary, without any further dependencies. | 40 - How to use |
42 It can be copied to another system and will no longer require Python or any of | 41 - [Running the test server](docs/usage/test-server.md) |
43 its modules. In order to generate the standalone test server you need all the | 42 - [Generating the standalone test server](docs/usage/standalone-test-server. md) |
44 prerequisites required to run the test server and | 43 - [Generating static files](docs/usage/generate-static-files.md) |
45 [PyInstaller](https://github.com/pyinstaller/pyinstaller/wiki). PyInstaller can | 44 - [Syncing translations](docs/usage/syncing-translations.md) |
46 be installed by running `easy_install pyinstaller`. | 45 - Content structure |
47 | 46 - [Configuration (`settings.ini`)](docs/structure/settings.md) |
Vasily Kuznetsov
2017/12/12 15:35:24
I think I prefer to call the folder `docs/content`
ire
2017/12/13 11:10:24
I agree. Done.
| |
48 Run the following command from the directory of the `cms` repository: | 47 - [Custom Jinja2 global functions and variables (`globals`)](docs/structure/ globals.md) |
49 | 48 - [Custom Jinja2 filters (`filters`)](docs/structure/filters.md) |
Vasily Kuznetsov
2017/12/12 15:35:25
This link is broken, the file is called `filter.md
ire
2017/12/13 11:10:23
Done.
| |
50 pyinstaller runserver.spec | 49 - [Localization files (`locales`)](docs/structure/locales.md) |
51 | 50 - [Page layout templates (`templates`)](docs/structure/templates.md) |
52 If successful, this will put the standalone test server into the `dist` | 51 - [Various include files (`includes`)](docs/structure/includes.md) |
53 directory. | 52 - [User-visible pages (`pages`)](docs/structure/pages.md) |
54 | 53 - [Static content (`static`)](docs/structure/static.md) |
55 ### Generating static files ### | 54 - API |
ire
2017/12/04 10:17:13
In the future I hope for the API documentation to
Vasily Kuznetsov
2017/12/12 15:35:24
Yeah, we need API documentation. Perhaps the part
ire
2017/12/13 11:10:23
I like this idea.
I arranged this into 3 files -
| |
56 | |
57 On your production server you should convert the content directory into static | |
58 files. To do that you need: | |
59 | |
60 * Python 2.7 | |
61 * [Jinja2](http://jinja.pocoo.org/) and | |
62 [Markdown](https://pypi.python.org/pypi/Markdown) modules (can be installed by | |
63 running `easy_install Jinja2 Markdown` from the command line) | |
64 * A current copy of the | |
65 [cms repository](https://github.com/adblockplus/cms/) (can be | |
66 [downloaded as ZIP file](https://github.com/adblockplus/cms/archive/master.zip ) | |
67 or cloned via `git clone https://github.com/adblockplus/cms.git`) | |
68 | |
69 Run the following command from the directory of the `cms` repository: | |
70 | |
71 python -m cms.bin.generate_static_pages www_directory target_directory | |
72 | |
73 Here `www_directory` should be replaced by the path to your content directory. | |
74 `target_directory` is the path where static files will be placed. | |
75 | |
76 Note: Localized versions of pages will only be generated when their translations | |
77 are at least 30% complete. (Measured by comparing the total number | |
78 of translatable strings on a page to the number of strings that have been | |
79 translated for a given locale.) This is different from the test server which | |
80 will include less complete translations. | |
81 | |
82 ### Syncing translations ### | |
83 | |
84 Before syncing translations ensure the following: | |
85 | |
86 - The `crowdin-project-name` setting has been set in the site's configuration. | |
87 - The `urllib3` Python module is installed. | |
88 | |
89 Now to sync with Crowdin type the following: | |
90 | |
91 python -m cms.bin.translate www_directory crowdin_project_api_key [logging_l evel] | |
92 | |
93 The script might take a while to run, it does the following things: | |
94 | |
95 1. Requests information about your Crowdin project | |
96 2. Checks all local locales are supported by Crowdin and enabled for your projec t | |
97 3. Renders all pages in your default language and extracts all page strings | |
98 4. Creates any required directories in your Crowdin project | |
99 5. Uploads any new page strings and updates any existing page strings | |
100 6. Uploads any pre-existing translation files for any newly uploaded pages | |
101 7. Requests Crowdin generate a fresh translations export archive | |
102 8. Downloads the archive of translations and extracts it replacing all local | |
103 translation files | |
104 | |
105 Notes: | |
106 | |
107 - You have to use the Crowdin project's API key, not your account API key | |
108 - You should probably enable "Skip untranslated strings" under your | |
109 project settings. | |
110 - Translations are only _uploaded_ for new files. If you are syncing with | |
111 Crowdin for the first time, and you have existing translation files pay | |
112 attention to any warnings. If there are any problems it is recommended | |
113 you re-create another fresh Crowdin project and try again. (Otherwise | |
114 translations for the pages already uploaded could be lost!) | |
115 - If you are running the script from a cronjob or similar you will probably | |
116 want to set the logging level to `ERROR` or similar | |
117 | |
118 ## Content structure ## | |
119 | |
120 Currently, the following directories of your content directory will be | |
121 considered: | |
122 | |
123 * `filters`: Custom Jinja2 filters | |
124 * `globals`: Custom Jinja2 global functions and variables | |
125 * `includes`: Various include files | |
126 * `locales`: Localization files | |
127 * `pages`: User-visible pages | |
128 * `static`: Static content | |
129 * `templates`: Page layout templates | |
130 | |
131 There should also be a `settings.ini` file with configuration. | |
132 | |
133 All of these are explained in more detail below. | |
134 | |
135 ### Configuration (settings.ini) ### | |
136 | |
137 The following sections can be defined in `settings.ini`: | |
138 | |
139 * `[general]`: following settings should be listed here: | |
140 * `defaultlocale`: The fallback locale, to be used whenever no localized | |
141 page/strings can be found for a locale. | |
142 * `defaultpage`: the default page which is displayed by the server if the URL | |
143 doesn't contain a page name. Note that while the test server will consider | |
144 that setting automatically, the real server might need to be configured | |
145 accordingly. | |
146 * `crowdin-project-name`: The Crowdin project name, this must be set for if | |
147 you intend to use the cms.bin.translate script to update the Crowdin | |
148 translations. | |
149 * `[langnames]`: defines the language names correspoding to particular language | |
150 codes. | |
151 * `[rtl]`: any language codes listed here are treated as right-to-left languages . | |
152 The values of the settings are ignored. | |
153 * `[locale_overrides]`: every entry defines that a page should use a different | |
154 locale file, not the one matching its name (to be used when multiple pages | |
155 share localization data). | |
156 | |
157 ### Localization files ### | |
158 | |
159 The language-specific data is stored in the `locales` directory. Each language | |
160 (identified by its locale code) is given a subdirectory here. The `.json` files | |
161 contain localizable strings using the following format: | |
162 | |
163 { | |
164 "stringid": { | |
165 "message": "Translated string", | |
166 "description": "Optional string description" | |
167 }, | |
168 ... | |
169 } | |
170 | |
171 Any other files are considered localizable files and will be available on the | |
172 server unchanged. This is useful for images for example: a language-dependent | |
173 image can be placed into the `locales/en` directory and a German version | |
174 of the same image into the `locales/de` directory. E.g. the file | |
175 `locales/en/foo.png` will be available on the server under the URL `/en/foo.png` . | |
176 | |
177 ### Pages ### | |
178 | |
179 The pages are defined in the `pages` directory. The file extension defines the | |
180 format in which a page is specified and won't be visible on the web server. | |
181 The page name is prepended by the locale code in the URL, e.g. `pages/foo.md` | |
182 can be available under the URLs `/en/foo` and `/de/foo` (the English and German | |
183 versions respectively). Regardless of the format, a page can define a number of | |
184 settings using the following format: | |
185 | |
186 setting = value | |
187 | |
188 Note that the settings have to placed at the beginning of the file, before the | |
189 actual content. The following settings can be changed: | |
190 | |
191 * `template`: This defines the template to be used for this page (without the | |
192 file extension). By default the `default` template is used for all pages. | |
193 * `title`: The locale string to be used as page title. By default the `title` | |
194 string is used. | |
195 * `noheading`: Setting this to any value will make sure no heading is displayed. | |
196 By default a `<h1>` tag with the page title is added above the content. | |
197 * `notoc`: Setting this to any value will prevent a table of contents from being | |
198 generated. By default a table of contents is always generated if the page | |
199 contains any headers with an `id` attribute. | |
200 | |
201 The following tag inserts an include file into the page (can be in a different | |
202 format): | |
203 | |
204 <? include foo ?> | |
205 | |
206 Include files should be placed into the `includes` directory of the repository. | |
207 In the case above the contents of `includes/foo.md` or `includes/foo.tmpl` will | |
208 be inserted (whichever is present). | |
209 | |
210 #### Markdown format (md) #### | |
211 | |
212 This format should normally be used, it allows the pages to be defined using the | |
213 [Markdown](http://daringfireball.net/projects/markdown/syntax) syntax. Raw HTML | |
214 tags are allowed and can be used where Markdown syntax isn't sufficient. The | |
215 [Python-Markdown Extra](https://pythonhosted.org/Markdown/extensions/extra.html) | |
216 extension is active and allows specifying custom attributes for the generated | |
217 HTML tags, HTML block elements that contain Markdown and more. | |
218 | |
219 Any content between `<head>` and `</head>` tags will be inserted into the head | |
220 of the generated web page, this is meant for styles, scripts and the like. | |
221 Other pages should be linked by using their name as link target (relative links) , | |
222 these links will be resolved to point to the most appropriate page language. | |
223 Embedding localizable images works the same, use the image name as image source. | |
224 | |
225 Localizable strings can be specified inline with the following syntax: | |
226 | |
227 {{string_name String contents in default language}} | |
228 | |
229 Try to give the string a descriptive name as it will help translators. | |
230 Optionally you can add a description for strings as well to provide even more | |
231 context: | |
232 | |
233 {{string_name[The string description] String contents}} | |
234 | |
235 _Note: String names and descriptions have no effect on the generated page, | |
236 assuming string name is unique to the page. The name and description are just | |
237 used to provide translators with additional context about the string._ | |
238 | |
239 Finally if you find yourself using the same string multiple times in a page | |
240 you can reduce duplication by simply omitting the description and contents | |
241 after the first use. For example: | |
242 | |
243 {{title[Title of the page] Adblock Plus - Home}} | |
244 {{title}} | |
245 | |
246 #### Raw HTML format (html) #### | |
247 | |
248 This format is similar to the Markdown format but uses regular HTML syntax. | |
249 No processing is performed beyond inserting localized strings and resolving | |
250 links to pages and images. This format is mainly meant for legacy content. | |
251 The syntax for localizable strings documented above can be used as with | |
252 Markdown. | |
253 | |
254 #### Jinja2 format (tmpl) #### | |
255 | |
256 Complicated pages can be defined using the | |
257 [Jinja2 template format](http://jinja.pocoo.org/docs/templates/). Automatic | |
258 escaping is active so by default values inserted into the page cannot contain | |
259 any HTML code. Any content between `<head>` and `</head>` tags will be inserted | |
260 into the head of the generated web page, everything else defined the content of | |
261 the page. | |
262 | |
263 The following variables can be used: | |
264 | |
265 * `page`: The page name | |
266 * `config`: Contents of the `settings.ini` file in this repository (a | |
267 [configparser object](http://docs.python.org/2/library/configparser.html)) | |
268 * `locale`: Locale code of the page language | |
269 * `available_locales`: Locale codes of all languages available for this page | |
270 | |
271 Following custom filters can be used: | |
272 | |
273 * `translate(default, name, comment=None)`: translates the given default string | |
274 and string name for the current page and locale. The string name should be | |
275 unique for the page but otherwise is only seen by the translators. Optionally | |
276 a comment (description) can be specified to help provide the translators with | |
277 additional context. | |
278 * `linkify(url, locale=None, **attrs)`: generates an `<a href="...">` tag for | |
279 the URL. If the URL is a page name it will be converted into a link to the | |
280 most appropriate page language. The language used can also be specified | |
281 manually with the locale parameter. Any further keyword arguments passed | |
282 are turned into additional HTML attributes for the tag. | |
283 * `toclist(html)`: extracts a list of headings from HTML code, this can be used | |
284 to generate a table of contents. | |
285 | |
286 The following global functions can be used: | |
287 | |
288 * `get_string(name, page=None)`: retrieves a string from a locale file. | |
289 Unless a page is specified the locale file matching the name of the current | |
290 page is used. | |
291 * `get_page_content(page, locale=None)`: returns a dictionary of the content | |
292 and params for the given page and locale. Locale defaults to the current one | |
293 if not specified. Provided keys include `head`, `body`, `available_locales` | |
294 and `translation_ratio`. | |
295 | |
296 ### Static files ### | |
297 | |
298 Any files located in the `static` directory will be available on the server | |
299 unchanged. The file `static/css/foo.css` will be available under the URL | |
300 `/css/foo.css`. | |
301 | |
302 ### Templates ### | |
303 | |
304 The templates specified in the `templates` directory specify the overall | |
305 structure that is common for all pages. These templates should have the file | |
306 extension `tmpl` and use the [Jinja2 template format](http://jinja.pocoo.org/doc s/templates/). | |
307 The differences to pages using the same format are: | |
308 | |
309 * No special treatment of the `<head>` tag. | |
310 * Additional variables `head` and `body` are defined with the HTML code that | |
311 should be added to the head and content of the page respectively. | |
312 | |
313 By default, `default.tmpl` will be used for all pages. If other templates are | |
314 defined, the pages need to choose them explicitly using the `template` setting. | |
315 | |
316 ### Custom filters ### | |
317 | |
318 The `filters` directory can define custom Jinja2 filters which will be available | |
319 in all Jinja2 templates. The file name defines the filter name, e.g. | |
320 `filters/myfilter.py` will define a filter named `myfilter`. This file should | |
321 also contain a function called `myfilter`, this one will be called when the | |
322 filter is invoked. For more information on Jinja2 filters see | |
323 [official documentation](http://jinja.pocoo.org/docs/dev/api/#writing-filters). | |
324 | |
325 ### Custom functions and variables ### | |
326 | |
327 The `globals` directory can define custom Jinja2 globals which will be available | |
328 in all Jinja2 templates. Typically, this is used for custom functions. The file | |
329 name should match the name of the function or variable to be defined, and export | |
330 a variable with that name. E.g. `globals/myfunction.py` can define a function | |
331 called `myfunction` that will become available to all Jinja2 templates. | |
OLD | NEW |