Skip to content

Commit

Permalink
fix: Weekdays and months correct translated
Browse files Browse the repository at this point in the history
Names of weekdays (in schedule settings) and months (in main windows timeline) now correct translated using the language setup.

It is realized with setting locale.LC_TIME based on the language code.

Fix #1729
  • Loading branch information
buhtz committed Jun 1, 2024
1 parent e6f7f4f commit e3c6771
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 100 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ env:
before_install:
# disable mongodb as we don't need it and it sometimes temporary fails
# https://github.com/travis-ci/travis-ci/issues/4937#issuecomment-149289729
- sudo rm -f /etc/apt/sources.list.d/mongodb.list
- sudo rm -f /etc/apt/sources.list.d/mongodb*.list
- sudo apt-key del 90CFB1F5
- sudo apt-get -qq update
# install screen, and util-linux (provides flock) for test_sshtools
- sudo apt-get install -y sshfs screen util-linux
Expand Down
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Back In Time

Version 1.4.4-dev (development of upcoming release)
* Fix: Names of weekdays and months translated correct (#1729)
* Fix: Global flock for multiple users (#1122, #1676)
* Fix bug: "Backup folders" list does reflect the selected snapshot (#1585) (@rafaelhdr Rafael Hurpia da Rocha)
* Breaking Change: GUI started with --debug does no longer add --debug to the crontab for scheduled profiles.
Expand Down
161 changes: 68 additions & 93 deletions common/doc-dev/1_doc_maintenance_howto.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Using Sphinx to write and build documentation
<sub>Feel free to [open issues](https://github.com/bit-team/backintime/issues) or contact the [maintenance team on the mailing list](https://mail.python.org/mailman3/lists/bit-dev.python.org/) if this text is difficult to understand or not helpful.</sub>
<sub>Feel free to [open issues](https://github.com/bit-team/backintime/issues)
or contact the
[maintenance team on the mailing
list](https://mail.python.org/mailman3/lists/bit-dev.python.org/)
if this text is difficult to understand or not helpful.</sub>

This file describes briefly how to
- build and view the source code "API" documentation of _Back In Time_
Expand All @@ -12,114 +16,76 @@ This file describes briefly how to

<!-- TOC start -->
- [Background](#background)
- [Why to use Sphinx to generate the
documentation?](#why-to-use-sphinx-to-generate-the-documentation)
- [How to build and view the
documentation](#how-to-build-and-view-the-documentation)
- [How to add new modules to the
documentation](#how-to-add-new-modules-to-the-documentation)
- [How to write docstrings for Back In
Time](#how-to-write-docstrings-for-back-in-time)
- [Commonly used rst markups in the
docstring](#commonly-used-rst-markups-in-the-docstring)
- [Known issues with documentation
generation](#known-issues-with-documentation-generation)
- [How to build and view the documentation](#how-to-build-and-view-the-documentation)
- [How to write docstrings for Back In Time](#how-to-write-docstrings-for-back-in-time)
- [How to add new modules to the documentation](#how-to-add-new-modules-to-the-documentation)
- [Commonly used rst markups in the docstring](#commonly-used-rst-markups-in-the-docstring)
- [Known issues with documentation generation](#known-issues-with-documentation-generation)
<!-- TOC end -->

# Background

The documentation is generated automatically from the docstrings
in the python source code files using the tool

Sphinx (https://www.sphinx-doc.org/en/master/)

together with the Sphinx-Extensions

- autodoc (to automatically generate rst doc files from the python docstrings)
https://www.sphinx-doc.org/en/master/man/sphinx-apidoc.html

- napoleon (to convert google-style docstrings to reStructuredText "rst" format required for autodoc)
https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html

- viewcode (to create links to browse the highlighted source code)
https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html

For a brief introduction to Sphinx for Python see:
https://betterprogramming.pub/auto-documenting-a-python-project-using-sphinx-8878f9ddc6e9

For a reference of rst markups see:
https://docutils.sourceforge.io/docs/user/rst/quickref.html

For a description of the Google coding style for python see:
https://google.github.io/styleguide/pyguide.html

# Why to use Sphinx to generate the documentation?

Sphinx has eg. the advantage to

- generate the documentation in different formats
(eg. html, PDF or Linux man pages).

- report invalid markups contained in the documentation

- inject documentation of attributes and methods from parent classes
into sub classes (in case of inheritance)
The documentation is generated automatically from the docstrings in the python
source code files using [Sphinx](https://www.sphinx-doc.org/en/master/) in
combination with the following Sphinx-Extensions:

- [autodoc](https://www.sphinx-doc.org/en/master/man/sphinx-apidoc.html) to
automatically generate rst doc files from the python docstrings.
- [napoleon](https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html)
to convert google-style docstrings to reStructuredText `rst` format
required for autodoc.
- [viewcode](https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html)
to create links to browse the highlighted source code.

Further readings:

- [Brief introduction to Sphinx for Python](https://betterprogramming.pub/auto-documenting-a-python-project-using-sphinx-8878f9ddc6e9)
- [Quick reference of rst markups](https://docutils.sourceforge.io/docs/user/rst/quickref.html)

# How to build and view the documentation

Open a terminal in the "doc-dev" folder and call
Open a terminal, navigate to the folder `common/doc-dev` and call

make html # to generate the HTML documentation
make htmlOpen # to open the browser showing the generated HTML pages

# How to write docstrings for _Back In Time_

_Back In Time_ uses the [Google style for
docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings).
Please stick to this convention. Look into documentation of
[`sphinx.ext.napoleon`](https://www.sphinx-doc.org/en/master/usage/extensions/example_google.html#example-google)
for extended examples.

# How to add new modules to the documentation

There are two scenarios here:


There are two scenarios:

a) The new module files are in a separate folder (not yet included in the doc generation so far)
## Scenario A: New module files are in a separate folder (not yet included in the doc generation so far)

- Add the python source code folder to the doc-dev/conf.py file
so that autodoc can find the files (navigate "relative" to the "doc-dev" folder)

- Generate the initial rst files for the new modules via "sphinx-apidoc", eg.
- Add the python source code folder to the file `doc-dev/conf.py` which is the
configuration. Then the `autodoc` extension is able to find the files
(navigate _relative_ to the `doc-dev` folder).
- Generate the initial `.rst` files for the new modules via `sphinx-apidoc`, eg.

sphinx-apidoc -o ./plugins ../plugins

to create a sub folder "doc-dev/plugins" with the rst files (one for each source file
in "doc-dev/../plugins"

- Add the new modules in the sub folder to the top-most "root" index.rst:

# under "modules.rst" add this line add a link to new modules
plugins/modules.rst
This example will create a sub folder `doc-dev/plugins` with the `.rst`
files (one for each source file) in `doc-dev/../plugins`.
- Add the new modules in the sub folder to the top-most _root_ `index.rst`:

# under "modules.rst" add this line add a link to new modules
plugins/modules.rst

## Scenario B: The new module files are in a folder that already contains other modules contained in the doc

b) The new module files are in a folder that already contains other modules contained in the doc

To create the initial version of rst files for new modules eg. in the "common" folder use
To create the initial version of `.rst` files for new modules eg. in the `common` folder use

sphinx-apidoc -o . ..

TODO: How to remove old rst files with non-existing python files (eg. due to renaming or deletion)
-> probably the -f ("force") argument could do this. Try it with -d ("dry-run")!



# How to write docstrings for _Back In Time_

_Back In Time_ uses the [Google style for
docstrings](https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings).
Please stick to this convention. Look into documentation of
[`sphinx.ext.napoleon` for an extended
example](https://www.sphinx-doc.org/en/master/usage/extensions/example_google.html#example-google).

_TODO_: How to remove old rst files with non-existing python files (eg. due to
renaming or deletion)? Probably the -f ("force") argument could do this. Try it
with -d ("dry-run")!

# Commonly used rst markups in the docstring

Expand All @@ -137,32 +103,41 @@ be used to format text and cross-reference code.

:py:func:`takeSnapshot`

Important: Don't forget to surround the function name with back ticks
otherwise Sphinx will not create a cross reference silently!
- Reference a module:

:py:module:`datetime`

- Specify the python type of an method/function argument:

Add the type name (with namespace if not in the same) in parentheses

Args:
cfg (config.Config): Current configuration
"""Short description...
Long description...
Args:
cfg (config.Config): Current configuration
"""

- Indicate python keywords (without cross-referencing them)
- To indicate verbatim text (inline code) enclose it with two backticks each.

``True``
``None``

Surround the keyword with two backticks (it will be shown as code then)

``de_DE.UTF-8``


# Known issues with documentation generation

- Sphinx' "make html" does not recreate the html file of a sub class if only
- Elements of PyQt can not be referenced. It is a [known
Issue](https://riverbankcomputing.com/pipermail/pyqt/2013-March/032528.html)
without an acceptable solution. Name them via verbatime text (two backticks)
only.

- Sphinx' ``make html`` does not recreate the html file of a sub class if only
the parent class docstring was changed.

Impact: Inherited documentation in the sub class is not up to date
_Impact_: Inherited documentation in the sub class is not up to date

Work around: Use "make clean" before "make html"
_Work around_: Use ``make clean`` before ``make html``

<sub>March 2023</sub>
<sub>May 2024</sub>
4 changes: 3 additions & 1 deletion common/doc-dev/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@
# -- Intersphinx options --------------------------------------------------

intersphinx_mapping = {
'python': ('https://docs.python.org', None),
'python': ('https://docs.python.org/3/', None),
# PyQt is not mappable because of a known issue. See
# https://riverbankcomputing.com/pipermail/pyqt/2013-March/032528.html
}

# -- Napoleon include private members which have docstrings ---------------
Expand Down
4 changes: 2 additions & 2 deletions common/doc-dev/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to BackInTime's documentation!
======================================
Welcome to Back In Time's documentation
=======================================

Contents:

Expand Down
52 changes: 50 additions & 2 deletions common/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import errno
import gzip
import tempfile
import locale
import gettext
try:
from collections.abc import MutableSet
Expand All @@ -38,7 +39,6 @@
from datetime import datetime
from packaging.version import Version
from time import sleep

import logger

# Try to import keyring
Expand Down Expand Up @@ -236,7 +236,55 @@ def initiate_translation(language_code):
)
translation.install(names=['ngettext'])

return _determine_current_used_language_code(translation, language_code)
used_code = _determine_current_used_language_code(
translation, language_code)

set_lc_time_by_language_code(used_code)

return used_code


def set_lc_time_by_language_code(language_code: str):
"""Set ``LC_TIME`` based on a specific language code.
Args:
language_code(str): A language code consisting of two letters.
The reason is to display correctly translated weekday and months
names. Python's :mod:`datetime` module, as well
``PyQt6.QtCore.QDate``, use :mod:`locale` to determine the
correct translation. The module :mod:`gettext` and
``PyQt6.QtCore.QTranslator`` is not involved so their setup does
not take effect.
Be aware that a language code (e.g. ``de``) is not the same as a locale code
(e.g. ``de_DE.UTF-8``). This function attempts to determine the latter based
on the language code. A warning is logged if it is not possible.
"""

# Determine the normalized locale code (e.g. "de_DE.UTF-8") by
# language code (e.g. "de").

# "de" -> "de_DE.ISO8859-1" -> "de_DE"
code = locale.normalize(language_code).split('.')[0]

try:
# "de_DE" -> "de_DE.UTF-8"
code = code + '.' + locale.getencoding()
except AttributeError: # Python 3.10 or older
code = code + '.' + locale.getpreferredencoding()

try:
logger.debug(f'Try to set locale.LC_TIME to "{code}" based on '
f'language code "{language_code}".')
locale.setlocale(locale.LC_TIME, code)

except locale.Error:
logger.warning(
f'Determined normalized locale code "{code}" (from language code '
f'"{code}" not available or invalid. The code will be ignored. '
'This might lead to unusual display of dates and timestamps, but '
'it does not affect the functionality of the application.')


def get_available_language_codes():
Expand Down
2 changes: 2 additions & 0 deletions qt/qttools.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,8 @@ def initiate_translator(language_code: str) -> QTranslator:
f'"{language_code}". Deactivate translation and falling back to '
'the source language (English).')

tools.set_lc_time_by_language_code(language_code)

return translator


Expand Down
3 changes: 2 additions & 1 deletion qt/settingsdialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,10 +488,11 @@ def __init__(self, parent):
self.comboScheduleWeekday = QComboBox(self)
glayout.addWidget(self.comboScheduleWeekday, 2, 1)

sunday = datetime.date(2011, 11, 6)
for d in range(1, 8):
self.comboScheduleWeekday.addItem(
QIcon(),
datetime.date(2011, 11, 6 + d).strftime("%A"),
(sunday + datetime.timedelta(days=d)).strftime('%A'),
d
)

Expand Down

0 comments on commit e3c6771

Please sign in to comment.