Files
TimeTracker/docs/CONTRIBUTING_TRANSLATIONS.md
T
Dries Peeters 05b6512a94 docs(i18n): link Drytrix TimeTracker Crowdin project and expand setup
Document https://crowdin.com/project/drytrix-timetracker in CONTRIBUTING.md, docs/TRANSLATION_SYSTEM.md, and contributor guides. Update CONTRIBUTING_TRANSLATIONS.md with the public project URL, clearer translator vs maintainer onboarding, and an optional "Further Crowdin integration" section (GitHub app, automation, QA, glossary, notifications).

Refresh crowdin.yml header comments (project URL, secrets pointers), normalize preserve_hierarchy to a boolean, and keep the nb→no languages_mapping quoted for YAML 1.1 compatibility.
2026-04-15 09:00:27 +02:00

10 KiB
Raw Blame History

Contributing translations (no Git required)

This project uses GNU gettext .po files under translations/<locale>/LC_MESSAGES/messages.po, compiled at app startup (see TRANSLATION_SYSTEM.md). You do not need Git or developer tools to suggest fixes.

How we accept help (channels)

Maintainers should pick what fits workload and community size. The default for this repository is A; scale up to B or C when needed.

Channel Best for Git?
A. GitHub issue (recommended default) Wrong/missing wording, one string or a small batch No — use the “Translation improvement” template when creating an issue
B. Spreadsheet or form Many rows at once, non-GitHub users No — maintainer copies suggestions into .po
C. Hosted translation platform Ongoing community, many languages, history and glossaries No for translators; maintainer connects repo or uploads .po

A. GitHub issue (primary)

  1. Open a new issue and choose Translation improvement.
  2. Fill in language, where you saw the text, current UI text, and your suggested wording.
  3. A maintainer updates the correct messages.po and merges the change.

No repository access is required.

B. Spreadsheet or form (optional)

Use when contributors cannot or will not use GitHub:

  1. Maintainer shares a table with columns such as: Language code, Screen or page, Text as shown now, Should be (your suggestion), Notes.
  2. Contributors only edit the suggestion column.
  3. Maintainer applies changes to the .po files and validates placeholders (see below).

C. Hosted platform (optional, higher volume)

Examples: Weblate (open source, can be self-hosted), Crowdin, POEditor, Transifex. Translators work in the browser; integration or export/import keeps .po in sync with the codebase. Setup is maintainer-owned.

TimeTracker on Crowdin: https://crowdin.com/project/drytrix-timetracker

Crowdin setup (maintainers)

This repo includes a root crowdin.yml that maps source translations/en/LC_MESSAGES/messages.po to translations under translations/<locale>/LC_MESSAGES/messages.po, with nbno so Norwegian matches app/config.py (no, not nb). You may still have a legacy translations/nb/ tree locally; prefer no in Crowdin and in config so you do not maintain two Norwegian copies.

  1. Crowdin account and projectSign up at Crowdin if needed. Translators work in Drytrix TimeTracker (ask a maintainer for access if the project is private). Maintainers configure API tokens and GitHub integration against that same project unless you intentionally use a separate test project.
  2. Source language: English. Treat the resource as Gettext PO (.po).
  3. Target languages: Add every locale you ship: nl, de, fr, it, fi, es, no, ar, he (match LANGUAGES in app/config.py). For Norwegian, add Norwegian (Bokmål) in Crowdin; the crowdin.yml mapping writes files into translations/no/.
  4. Sync with this repository (pick one):
    • GitHub Action: In the GitHub repo, add Actions secrets CROWDIN_PROJECT_ID and CROWDIN_PERSONAL_TOKEN (Crowdin project Details shows the numeric project ID; Account Settings → API creates the token with project access, typically Manager). Run Crowdin sync from the Actions tab → Run workflow. For a one-time import of existing .po files into Crowdins translation memory, temporarily set upload_translations: true in .github/workflows/crowdin-sync.yml, run it once, then set it back to false.
    • Crowdins GitHub integration: Crowdin → Integrations → GitHub → connect the repo and branch; point it at the same crowdin.yml so Crowdin can open PRs when translations are updated.
    • Crowdin CLI: Install the Crowdin CLI, export the same env vars, run crowdin upload sources (and optionally crowdin upload translations once) from the repository root.
  5. When developers add or change _() strings: Run pybabel extract / pybabel update locally (see TRANSLATION_SYSTEM.md), commit if you version those files, then upload sources to Crowdin again.
  6. Landing translations: Approve in Crowdin if you use review, then download (workflow or integration PR), merge, and run the app so .mo files rebuild.

Translators only need a Crowdin account; they do not use git.

Further Crowdin integration (optional)

Pick what reduces manual work without duplicating automation (avoid running both the Crowdin GitHub app and the Crowdin sync Action on the same events unless you coordinate branches, or you may get competing PRs).

  1. Crowdin → Integrations → GitHub — Connect the repository and default branch (e.g. main or develop). Crowdin can open PRs when translations are updated and can watch the repo for changes to configured source files. Use the same crowdin.yml path the integration expects (usually repo root). This can replace manual Action runs for “download translations” if you prefer Crowdin-driven PRs.
  2. Automate the existing Action — Extend .github/workflows/crowdin-sync.yml with triggers such as schedule (e.g. weekly), or push limited to translations/en/** and messages.pot so new English sources upload shortly after merge. Keep workflow_dispatch for on-demand full sync.
  3. Pre-translate and QA — In the Drytrix TimeTracker project, enable Translation Memory, Machine translation (as a suggestion layer only), and QA checks (variables, HTML tags, duplicate translations). Add a Glossary for product names and fixed terminology.
  4. Context for translators — Upload screenshots or use Crowdins in-context / overlay tools where supported so ambiguous short strings (e.g. “Save”, “Project”) get the right meaning.
  5. Review before merge — Turn on proofreading / “Export only approved” in Crowdin if you want the GitHub Action or integration to pull only reviewed strings (match the Actions export_only_approved-style options to your Crowdin workflow).
  6. CLI in release process — Add crowdin upload sources after pybabel extract / update in a maintainer script or release checklist so Crowdin always matches the latest POT-derived English catalog.
  7. Notifications — Slack, email, or webhooks in Crowdin when a language reaches 100% or when there are new strings to translate.

Official references: Crowdin + GitHub, GitHub Action, Crowdin CLI.

Other options (reference)

  • Poedit: Maintainer can zip translations/<lang>/LC_MESSAGES/messages.po for a trusted translator; they edit in Poedit and send the file back. Avoid two people editing the same locale in parallel without coordination.
  • GitHub web editor on .po files: Possible for experts only; easy to break quoting or plural blocks.

Rules for translators

Follow these so your suggestion can be applied without breaking the app:

  1. Do not change English source keys. In .po files those are msgid lines. In an issue or spreadsheet you describe what you see; maintainers map it to the file. Never invent a new English “key” string.
  2. Preserve placeholders exactly. If the UI shows Hello, %(username)s or similar, your translation must include the same placeholders (same names, same %(name)s-style segments). Same for %s, %d, or other format tokens.
  3. Plurals: Some strings have one vs many forms. If you are unsure, describe the case in Notes and a maintainer will set msgstr[0] / msgstr[1] correctly in the .po file.
  4. Context matters. Say which page, button, or dialog the text appears on, and attach a screenshot if possible. One English phrase can appear in multiple places with different meanings.
  5. Length and tone: Short labels (buttons, nav) should stay compact. Full sentences can be more natural in your language than literal word-for-word English.

Supported locale codes (see app/config.py LANGUAGES): en, nl, de, fr, it, fi, es, no, ar, he.

Maintainer workflow

Designate at least one person responsible for translation intake (issues, spreadsheet, or platform export).

Applying contributor suggestions

  1. Identify the locale file: translations/<locale>/LC_MESSAGES/messages.po.
  2. Find the entry (by msgid / English source or grep for the current msgstr).
  3. Update msgstr (and plural msgstr[n] if needed). Remove #, fuzzy if you are sure the translation is correct (fuzzy entries may be ignored at compile time depending on setup).
  4. Restart the app or trigger your usual deploy so .mo is regenerated (see TRANSLATION_SYSTEM.md — compilation runs on startup via app/utils/i18n.py).

After new UI strings ship in code

When developers add or change translatable strings:

pybabel extract -F babel.cfg -o messages.pot .
pybabel update -i messages.pot -d translations

Then fill new empty entries in each messages.po, run the app, and smoke-test critical screens in a few locales.

Verification checklist

  • Placeholders in msgstr match the msgid / source string.
  • .po file is valid UTF-8 and parses (Poedit or msgfmt --check).
  • UI checked in the target language for overflow or clipping on small screens (especially for short buttons).

See also