Skip to content
Merged
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
29 changes: 29 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,35 @@ Kontakt: `security@<your-domain>` oder GitHub Security Advisory

---

## 🌍 Translations (i18n)

OpenCloudTouch uses [react-i18next](https://react.i18next.com/) for internationalization.
See [docs/adr/007-i18n.md](../docs/adr/007-i18n.md) for the full library decision.

### Source of Truth

**`apps/frontend/src/i18n/locales/en.json` is the single source of truth for all UI strings.**

Rules:
- Every user-visible string MUST exist in `en.json` before it appears in any component
- German translation lives in `de.json` and must be kept in sync
- New strings go to `en.json` first, then are translated in `de.json` (and any other locale)
- Never hardcode English text directly in components — always use `t("key")`

### Adding a new UI string

1. Add the key to `apps/frontend/src/i18n/locales/en.json`
2. Add the German translation to `apps/frontend/src/i18n/locales/de.json`
3. Add translations for any other supported locales (`fr.json`, `it.json`, …)
4. Use `const { t } = useTranslation()` + `t("your.new.key")` in the component

### Contributing a new language

Use the **[Translation Contribution](https://github.com/scheilch/opencloudtouch/issues/new?template=translation_contribution.yml)** issue template.
You do not need to open a PR — paste your translated JSON into the issue and a maintainer will create the locale file.

---

## 📚 Dokumentation

Bei Code-Änderungen bitte auch Doku aktualisieren:
Expand Down
61 changes: 61 additions & 0 deletions .github/ISSUE_TEMPLATE/translation_contribution.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: "Translation Contribution: [Language]"
description: Contribute translations for a new or existing language
title: "Translation Contribution: [Language]"
labels: ["i18n", "help wanted"]
body:
- type: input
id: language_name
attributes:
label: Language Name
description: The full English name of the language (e.g. "Spanish", "French")
placeholder: "e.g. Spanish"
validations:
required: true

- type: input
id: locale_code
attributes:
label: Locale Code (ISO 639-1)
description: The 2-letter ISO 639-1 code for the language
placeholder: "e.g. es"
validations:
required: true

- type: input
id: completeness
attributes:
label: Completeness (%)
description: Approximately what percentage of keys are translated?
placeholder: "e.g. 100"
validations:
required: true

- type: textarea
id: translations
attributes:
label: Translated en.json snippet
description: >
Paste your translated JSON matching the structure of
`apps/frontend/src/i18n/locales/en.json`. You can provide a full
translation or a partial one — mark missing values with the English
string.
render: json
placeholder: |
{
"common": {
"save": "Guardar",
"cancel": "Cancelar"
}
}
validations:
required: true

- type: textarea
id: notes
attributes:
label: Notes
description: >
Any additional notes, regional variants, or open questions about the
translation (optional).
validations:
required: false
15 changes: 10 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ name: CI
on:
push:
branches:
- '**'
- main

pull_request:
branches:
- '**'
types: [opened, synchronize, reopened]

workflow_dispatch:

jobs:
Expand Down Expand Up @@ -180,7 +181,9 @@ jobs:
if: always()
with:
name: backend-coverage
path: .out/coverage/backend/coverage.json
path: |
.out/coverage/backend/coverage.json
.out/coverage/backend/coverage.xml
retention-days: 1

# ============================================================================
Expand Down Expand Up @@ -225,7 +228,9 @@ jobs:
if: always()
with:
name: frontend-coverage
path: .out/coverage/frontend/coverage-summary.json
path: |
.out/coverage/frontend/coverage-summary.json
.out/coverage/frontend/lcov.info
retention-days: 1

# ============================================================================
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/sonar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened]
schedule:
- cron: '0 6 * * 1' # Every Monday 6:00 UTC
# NOTE: PR analysis is handled by the sonar job in ci.yml (which uses
# pre-built coverage artifacts). Do NOT add pull_request trigger here
# — it would create a competing scan that overwrites coverage results.
jobs:
sonarqube:
name: SonarQube
Expand Down
80 changes: 80 additions & 0 deletions apps/backend/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2531,6 +2531,42 @@ paths:
content:
application/json:
schema: {}
/api/logs/backend:
get:
tags:
- logs
summary: Download Backend Log
description: Returns the in-memory backend log as a plain-text file download.
operationId: download_backend_log_api_logs_backend_get
responses:
'200':
description: Plain-text log file download
content:
text/plain:
schema:
type: string
/api/bug-report:
post:
tags:
- bug-report
summary: Submit Bug Report
description: Submit a bug report that creates a GitHub issue with diagnostic data.
operationId: submit_bug_report_api_bug_report_post
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/BugReportRequest'
responses:
'200':
description: Bug report submitted successfully
content:
application/json:
schema:
$ref: '#/components/schemas/BugReportResponse'
'503':
description: GitHub token not configured
components:
schemas:
BackupRequest:
Expand Down Expand Up @@ -2570,6 +2606,50 @@ components:
- message
title: BackupResponse
description: Response with backup results.
BugReportRequest:
type: object
required:
- description
- steps_to_reproduce
- expected_behavior
- installation_type
- hardware
properties:
description:
type: string
minLength: 20
steps_to_reproduce:
type: string
minLength: 10
expected_behavior:
type: string
minLength: 10
installation_type:
type: string
hardware:
type: string
soundtouch_devices:
type: array
items:
type: string
default: []
other_installation:
type: string
default: ''
other_hardware:
type: string
default: ''
title: BugReportRequest
BugReportResponse:
type: object
properties:
issue_url:
type: string
issue_number:
type: integer
message:
type: string
title: BugReportResponse
Body_set_mute_api_devices__device_id__mute_put:
properties:
muted:
Expand Down
Loading
Loading