Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ kwin/build-test/
kwin/src/qml/calibrating.png
kwin/src/qml/custom_banner.png
kwin/src/kcm/com.xronlinux.BreezyDesktop.svg
kwin/po/*/LC_MESSAGES/
184 changes: 184 additions & 0 deletions kwin/TRANSLATING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# Translation guide for the Breezy Desktop KWin KCM

This document covers:
1. [Instructions for translators](#instructions-for-translators) — how to translate the KCM UI into your language
2. [Maintainer workflow](#maintainer-workflow) — how to keep translations up to date as strings change

---

## Instructions for translators

### Supported languages

The following languages are currently listed in `kwin/po/LINGUAS`. If yours is
missing, follow the steps below and open a pull request — new languages are
welcome.

| Code | Language |
|---------|-----------------------|
| `de` | German |
| `es` | Spanish |
| `fr` | French |
| `it` | Italian |
| `ja` | Japanese |
| `pl` | Polish |
| `pt_BR` | Portuguese (Brazil) |
| `ru` | Russian |
| `sv` | Swedish |
| `uk_UA` | Ukrainian |
| `zh_CN` | Chinese (Simplified) |

### What to translate

All translatable strings for the KDE Control Module (KCM) live in:

```
kwin/po/<lang>/breezy_desktop_kwin.po
```

Each file is a standard **GNU gettext PO** file. You only need a plain-text
editor to work with it (though dedicated PO editors like
[Lokalize](https://apps.kde.org/lokalize/),
[Poedit](https://poedit.net/), or
[Virtaal](https://virtaal.translatehouse.org/) make the job easier).

### Step-by-step

1. **Clone the repository** (or fork it on GitHub):
```bash
git clone https://github.com/wheaney/breezy-desktop.git
```

2. **Open your language's PO file** in your editor, for example:
```
kwin/po/de/breezy_desktop_kwin.po
```
If your language is not listed yet, copy the template:
```bash
cp kwin/po/breezy_desktop_kwin.pot kwin/po/<lang>/breezy_desktop_kwin.po
```
Then fill in the `Language:` header and the `Plural-Forms:` header.
You can look up the correct plural form for your language at
<https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html>.

3. **Translate each `msgstr ""`** entry. Leave `msgid` untouched — it is the
English source string.

```po
# Before
msgid "No device connected"
msgstr ""

# After
msgid "No device connected"
msgstr "Kein Gerät verbunden"
```

**Things to keep in mind:**
- Strings containing `%1`, `%2`, … are placeholders. You may reorder them
in the translation if your language requires a different word order, but
every placeholder present in `msgid` must also appear in `msgstr`.
- Tab titles prefixed with `&` (e.g. `"&General"`) use that character as a
keyboard accelerator. You may move the `&` to a different letter that
makes sense in your language.
- Strings marked with `notr="true"` in the source `.ui` files are not
extracted and do not appear in the PO file — you don't need to worry about
them.
- The `Author:` and `License:` lines in the About tab may be left unchanged
if the format already makes sense in your language.

4. **Update your name and contact** in the PO file header:
```po
"Last-Translator: Your Name <you@example.com>\n"
"Language-Team: German\n"
```

5. **Submit your changes** by opening a pull request on GitHub.

---

## Maintainer workflow

### Prerequisites

```bash
sudo apt-get install kdesdk-scripts gettext # Debian / Ubuntu
# or
sudo dnf install kf6-kdesdk-scripts gettext # Fedora
```

`kdesdk-scripts` provides `extractrc`, which converts Qt Designer `.ui` files
into a temporary C++ file that `xgettext` can process.

### Updating translations after string changes

Whenever you add, remove, or change a user-visible string in the KCM source
(`src/kcm/*.cpp`, `src/kcm/*.h`, `src/kcm/*.ui`), run the dev script:

```bash
kwin/bin/update_pot_files
```

This script will:

1. Run `extractrc` on all `.ui` files to capture strings wrapped by
`ki18n_wrap_ui`.
2. Run `xgettext` on the C++ sources (using KDE i18n keywords such as
`i18n()`, `I18N_NOOP()`, etc.) to extract all translatable strings into
`kwin/po/breezy_desktop_kwin.pot`.
3. Run `msgmerge` on each per-language `.po` file to pull in new strings and
mark removed strings as obsolete.
4. Compile each updated `.po` file to a binary `.mo` file under
`kwin/po/<lang>/LC_MESSAGES/` for local testing.

After running the script, **review the changes** to
`kwin/po/breezy_desktop_kwin.pot` and each `.po` file, then commit them.
Translators can then update their language files with the new `msgid` entries
that appear with empty `msgstr ""`.

### Adding a new language

1. Add the language code to `kwin/po/LINGUAS` (space-separated, on one line).
2. Run `kwin/bin/update_pot_files` — it will create
`kwin/po/<lang>/breezy_desktop_kwin.po` automatically.
3. Commit the new file and invite a native speaker to fill in the translations.

### Adding new translatable strings in C++

Use `i18n()` (or `ki18n()`, `i18nc()`, etc.) from `<KLocalizedString>`.
**Do not** use Qt's `tr()` or `QObject::tr()` — they bypass the KDE i18n
infrastructure and are not extracted into the PO files.

```cpp
// ✓ Correct
#include <KLocalizedString>
label->setText(i18n("No device connected"));
label->setText(i18n("Version %1", versionString));

// ✗ Wrong — not extracted, not translated
label->setText(tr("No device connected"));
label->setText(QStringLiteral("No device connected"));
```

For strings in `.ui` files, `ki18n_wrap_ui()` in CMake handles the wrapping
automatically at build time — just write normal `<string>` elements. If a
string should *not* be translated (e.g. a CSS stylesheet or a numeric
placeholder), add `notr="true"`:

```xml
<property name="styleSheet">
<string notr="true">color: rgb(200,0,0); font-weight: bold;</string>
</property>
```

For constant strings defined at file or namespace scope (e.g. keyboard
shortcut labels), use `I18N_NOOP()` in the header to mark them for extraction,
and call `i18n()` on them at the point of use:

```cpp
// shortcuts.h
const char *actionText = I18N_NOOP("Toggle XR Effect");

// usage site
action->setText(i18n(shortcut.actionText));
```
80 changes: 80 additions & 0 deletions kwin/bin/update_pot_files
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/usr/bin/env bash
#
# update_pot_files — extract translatable strings from the KCM source, update
# all per-language .po files, and regenerate any compiled .mo files.
#
# Run this script whenever you add or change translatable strings in:
# - kwin/src/kcm/*.cpp / *.h (i18n(), I18N_NOOP(), …)
# - kwin/src/kcm/*.ui (Qt Designer UI files)
#
# Requirements:
# extractrc – part of kdesdk-scripts (Debian/Ubuntu: kdesdk-scripts)
# xgettext – part of gettext
# msgmerge – part of gettext
# msgfmt – part of gettext
#
# Quick install on Debian/Ubuntu:
# sudo apt-get install kdesdk-scripts gettext

set -euo pipefail

SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)

# Operate from the kwin/ root so relative paths in the .pot match src/
pushd "$SCRIPT_DIR/.." > /dev/null

if ! command -v extractrc &>/dev/null; then
echo "ERROR: 'extractrc' not found." >&2
echo "Install it with: sudo apt-get install kdesdk-scripts" >&2
popd > /dev/null
exit 1
fi

if ! command -v xgettext &>/dev/null || ! command -v msgmerge &>/dev/null || ! command -v msgfmt &>/dev/null; then
echo "ERROR: gettext tools not found (xgettext, msgmerge, msgfmt)." >&2
echo "Install them with: sudo apt-get install gettext" >&2
popd > /dev/null
exit 1
fi

DOMAIN="breezy_desktop_kwin"
POT="po/${DOMAIN}.pot"
TMP_RC=$(mktemp /tmp/kcm-rc-XXXXXX.cpp)
trap 'rm -f "$TMP_RC"' EXIT

# 1. Extract strings from Qt Designer .ui files via extractrc, which converts
# them into i18n() C++ calls that xgettext understands.
extractrc src/kcm/*.ui > "$TMP_RC"

# 2. Extract all translatable strings into the .pot template.
xgettext \
--from-code=UTF-8 \
--language=C++ \
-ki18n:1 -ki18nc:1c,2 -ki18np:1,2 -ki18ncp:1c,2,3 \
-kki18n:1 -kki18nc:1c,2 -kki18np:1,2 -kki18ncp:1c,2,3 \
-kI18N_NOOP:1 -kI18N_NOOP2:1c,2 -kI18NC_NOOP:1c,2 \
-ktr2i18n:1 \
--package-name="breezy-desktop" \
--msgid-bugs-address="https://github.com/wheaney/breezy-desktop/issues" \
-o "$POT" \
src/kcm/*.cpp src/kcm/*.h "$TMP_RC"

echo "Updated $POT"

# 3. Merge the updated template into each per-language .po file and recompile.
for lang in $(cat po/LINGUAS); do
PO="po/${lang}/${DOMAIN}.po"
mkdir -p "po/${lang}"
if [ -f "$PO" ]; then
msgmerge --no-fuzzy-matching --update "$PO" "$POT"
else
msginit --no-translator --locale="${lang}" --input="$POT" --output="$PO"
fi

# Compile to binary .mo for local testing
outdir="po/${lang}/LC_MESSAGES"
mkdir -p "$outdir"
msgfmt -o "$outdir/${DOMAIN}.mo" "$PO"
done

popd > /dev/null
1 change: 1 addition & 0 deletions kwin/po/LINGUAS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
de es fr it ja pl pt_BR ru sv uk_UA zh_CN
Loading