diff --git a/README.md b/README.md index f4509d6..de4c6f4 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,26 @@ # Custom files for git.friendi.ca These files are the cutsom files for git.friendi.ca. -They are overriding the default template files of gitea +They are overriding the default template files of gitea. +The content of `custom` needs to be placed in `/var/lib/gitea` (at least at git.friendi.ca). ## Translation Translation of the strings can be done at [Transifex](https://www.transifex.com/Friendica/friendica/) with the rest of the project resources. + +## Workflow + +1. Update the strings at the top of the `generate_home_tmpl.py` file, those that start with a `str_` in the name. +2. Extract them with `pygettext -p ./lang/C/ generate_home_tmpl.py` +3. Commit the new `messages.pot` file and push it to the repository at git.friendi.ca +4. Wait for Transifex to pick up the changes and the translation teams to make the new translations +5. Download the finished translations to `lang/$lngcode/LC_MESSAGES/messages.pot` +6. Edit the `messages.pot` file and set the characterset to UTF-8. + `"Content-Type: text/plain; charset=UTF-8\n"` +7. Convert the `messages.pot` file to `messages.mo` using `msgfmt messages.pot` +8. Run `python3 generate_home_tmpl.py` it will recreate the `custom/templates/home.tmpl` file +9. Upload that file and copy it to the `custom/templates/` directory of the gitea instance. + +## License + +The python script to generate the template file has been released under the terms of the MIT license. diff --git a/generate_home_tmpl.py b/generate_home_tmpl.py new file mode 100644 index 0000000..2b2aaa5 --- /dev/null +++ b/generate_home_tmpl.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Script to generate the gitea landing page for git.friendi.ca with strings +from the translation files. The generated 'home.tmpl' then has to be +placed into the 'custom/templates' directory of the gitea installation. + +Authors: +* Tobias Diekershoff + +Copyright (c) 2018 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" +import gettext +import os + +# define dummy _ function for pygettext to find the translate-able strings +def _(message): return message + +# constant strings for the webpage +str_collection = _("Collection of the git repositories of the Friendica project.") +str_header1 = _("Easy to install") +str_box1 = _("All you need is PHP and a MySQL database. Installation can be done via file upload, git or docker.") +str_header2 = _("Free Software") +str_box2 = _("Friendica is Free Software, licensed under the terms of the AGPLv3 (or later). The entire source code is hosted at git.friendi.ca. Join us by contributing to make this project even better. Don't be shy to be a contributor!") +str_header3 = _("Decentralization") +str_box3 = _("Decentralized architecture with no central authority or ownership. Relationships can be made across any compatible system, creating a network of Internet scale made up of smaller sites. Seamless wall-to-wall posts and remote comments, even across different network nodes.") +str_header4 = _("Interoperability") +str_box4 = _("Friendica has build in support for the OStatus (e.g. GNU social and Mastodon) and diaspora* (e.g. diaspora*, Hubzilla and Socialhome) protocol. With additional addons you can bridge to more networks like pump.io, Twitter and others.") + +# we don't need the dummy anymore +del _ + +# which translations do we have? and where to find them +myDomain = "messages" +languageDirectory = 'lang' +fn = os.path.join(os.path.abspath(os.path.dirname(__file__)), languageDirectory) +# once there are translations, this list is used to hold the lng-codes +# of the available translations. Later in the script, when the home.tmpl +# is created, we'll loop over all these languages. +translations = ['de-DE', 'nl-NL', 'it-IT', 'pl-PL', 'cs-CZ'] +count = len(translations) +languages = {} +# read in all the available translation for later usage +for lng in translations: + l = gettext.translation(domain=myDomain, localedir=fn, languages=[lng]) + languages[lng] = l +# for the beginning and ending of the if ... else if ... else cascade +ifelse = {0: '\n{{if eq .Lang "{{lngcode}}"}}\n', count: '\n{{else}}\n'} +# The icons from font awesome used for the four info box titles +icons = {'ul' : '', + 'ur' : '', + 'll' : '', + 'lr' : ''} +# header block of the template +templateHead = """{{template "base/head" .}} +
+
+
+
+ +
+
+

+ Friendica +

+""" +# template for the subtitle in the header +templateCollection = "

{{CollectionOfRepositories}}

" +# closing the header +templateMedium = """ +
+
+
+""" +# The info boxes, there are four in total, this template holds 2 divs (left and right) +templateInfoBox = """
+
+

+ {{Licon}} {{Lheader}} +

+

+ {{Lbody}} +

+
+
+

+ {{Ricon}} {{Rheader}} +

+

+ {{Rbody}} +

+
+
+""" +# closing the page +templateFooter = """
+{{template "base/footer" .}} +""" + +# templates and preparation done, generate the home.tmpl file containing all ready languages +with open('custom/templates/home.tmpl', mode='w', encoding='utf-8') as outFile: + outFile.write(templateHead) + if count: + for i in range(count+1): + try: + # for all languages except the default + lng = translations[i] + l = languages[translations[i]] + _ = l.gettext + l.install() + outString = _(str_collection) + except: + # last entry in the cascade is the default (EN) language + lng = 'en' + outString = str_collection + if i in [0, count]: + # opening and ending of the if ... else if ... else cascade need special treatment + outFile.write(ifelse[i].replace('{{lngcode}}', lng)) + else: + outFile.write('\n{{else if eq .Lang "{{lngcode}}"}}\n'.replace('{{lngcode}}', lng)) + outFile.write(templateCollection.replace("{{CollectionOfRepositories}}", outString)) + outFile.write('\n{{end}}\n') + else: + # if not, we just take the line for the base language + outFile.write(templateCollection.replace("{{CollectionOfRepositories}}", str_collection)) + outFile.write(templateMedium) + # now add the info boxes in all translations and the base language + if count: + for i in range(count+1): + try: + lng = translations[i] + l = languages[translations[i]] + _ = l.gettext + l.install() + except: + lng = 'en' + if i in [0, count]: + # opening and ending of the if ... else if ... else cascade need special treatment + outFile.write(ifelse[i].replace('{{lngcode}}', lng)) + else: + outFile.write('\n{{else if eq .Lang "{{lngcode}}"}}\n'.replace('{{lngcode}}', lng)) + if not i == count: + # a translation + # upper row of info boxes + tmpText = templateInfoBox.replace('{{Licon}}', icons['ul']).replace('{{Ricon}}', icons['ur']) + tmpText = tmpText.replace('{{Lheader}}', _(str_header1)).replace('{{Rheader}}', _(str_header2)) + tmpText = tmpText.replace('{{Lbody}}', _(str_box1)).replace('{{Rbody}}', _(str_box2)) + outFile.write(tmpText) + # lower row of info boxes + tmpText = templateInfoBox.replace('{{Licon}}', icons['ll']).replace('{{Ricon}}', icons['lr']) + tmpText = tmpText.replace('{{Lheader}}', _(str_header3)).replace('{{Rheader}}', _(str_header4)) + tmpText = tmpText.replace('{{Lbody}}', _(str_box3)).replace('{{Rbody}}', _(str_box4)) + outFile.write(tmpText) + else: + # finally the default language + # upper row of info boxes + tmpText = templateInfoBox.replace('{{Licon}}', icons['ul']).replace('{{Ricon}}', icons['ur']) + tmpText = tmpText.replace('{{Lheader}}', str_header1).replace('{{Rheader}}', str_header2) + tmpText = tmpText.replace('{{Lbody}}', str_box1).replace('{{Rbody}}', str_box2) + outFile.write(tmpText) + # lower row of info boxes + tmpText = templateInfoBox.replace('{{Licon}}', icons['ll']).replace('{{Ricon}}', icons['lr']) + tmpText = tmpText.replace('{{Lheader}}', str_header3).replace('{{Rheader}}', str_header4) + tmpText = tmpText.replace('{{Lbody}}', str_box3).replace('{{Rbody}}', str_box4) + outFile.write(tmpText) + outFile.write('\n{{end}}\n') + else: + # if not, it is only the base language + # upper row of info boxes + tmpText = templateInfoBox.replace('{{Licon}}', icons['ul']).replace('{{Ricon}}', icons['ur']) + tmpText = tmpText.replace('{{Lheader}}', str_header1).replace('{{Rheader}}', str_header2) + tmpText = tmpText.replace('{{Lbody}}', str_box1).replace('{{Rbody}}', str_box2) + outFile.write(tmpText) + # lower row of info boxes + tmpText = templateInfoBox.replace('{{Licon}}', icons['ll']).replace('{{Ricon}}', icons['lr']) + tmpText = tmpText.replace('{{Lheader}}', str_header3).replace('{{Rheader}}', str_header4) + tmpText = tmpText.replace('{{Lbody}}', str_box3).replace('{{Rbody}}', str_box4) + outFile.write(tmpText) + outFile.write(templateFooter) + outFile.close()