Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ab4684e
Refactor i18n to use ICU and sentences where possible
marcosinigaglia Oct 24, 2025
80b0052
Merge remote-tracking branch 'upstream/main' into feat/locale-improve…
marcosinigaglia Nov 10, 2025
2da0d7e
Update pnpm-lock.yaml
marcosinigaglia Nov 10, 2025
28b1ff5
Merge remote-tracking branch 'upstream/main' into feat/locale-improve…
marcosinigaglia Nov 11, 2025
d2aa059
Merge branch 'main' into feat/locale-improvements
marcosinigaglia May 18, 2026
faeb5e1
Update .gitignore
marcosinigaglia May 18, 2026
b6a8de5
Merge remote-tracking branch 'upstream/main' into feat/locale-improve…
marcosinigaglia Aug 11, 2026
034c22f
refactor(i18n): migrate translations to ICU message format
marcosinigaglia Aug 11, 2026
2294dbd
Merge remote-tracking branch 'upstream/main' into feat/locale-improve…
marcosinigaglia Aug 11, 2026
28f1561
fix(i18n): restore ICU messages after upstream merge
marcosinigaglia Aug 11, 2026
4ac2974
style: format files with Prettier
marcosinigaglia Aug 11, 2026
ae6a828
fix: avoid shadowing open state
marcosinigaglia Aug 11, 2026
8e1053c
fix: avoid inline submit handler in confirmation dialog
marcosinigaglia Aug 11, 2026
4bf4f66
Remove bundled locale JSON files
marcosinigaglia Aug 18, 2026
b631ee9
Merge remote-tracking branch 'upstream/main' into feat/locale-improve…
marcosinigaglia Aug 18, 2026
c9ab5fb
Update public/locales/it/common_icu.json
marcosinigaglia Aug 18, 2026
e896e34
Update src/utils/strings.ts
marcosinigaglia Aug 18, 2026
c09d2d9
Added missing key
marcosinigaglia Aug 18, 2026
6e440b0
Merge branch 'feat/locale-improvements' of https://github.com/marcosi…
marcosinigaglia Aug 18, 2026
e03a072
Preserve source balance direction and use session user for roles
marcosinigaglia Aug 18, 2026
bb87639
fix: show error toast when preferred language update fails
marcosinigaglia Aug 18, 2026
2a4a227
fix: enforce controlled confirmation dialog props
marcosinigaglia Aug 18, 2026
249c752
docs: add docstrings for locale resolution helpers
marcosinigaglia Aug 18, 2026
9c6ca04
refactor: limit ICU migration to existing translation catalogs
marcosinigaglia Oct 7, 2026
8976918
Merge remote-tracking branch 'upstream/main' into feat/locale-improve…
marcosinigaglia Oct 12, 2026
be854c4
fix(i18n): restore ICU messages and resolve UI regressions
marcosinigaglia Oct 12, 2026
5621339
fix(test): validate random bounds in percentage split test
marcosinigaglia Oct 12, 2026
4339e28
fix(recurring): format each expense amount in its own currency
marcosinigaglia Oct 12, 2026
66adb48
Merge remote-tracking branch 'upstream/main' into feat/locale-improve…
marcosinigaglia Oct 13, 2026
55ffbfd
Add note about doc removal
krokosik Oct 13, 2026
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
62 changes: 62 additions & 0 deletions docs/OBSOLETE_TRANSLATION_KEYS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Obsolete translation keys

Remove in part 2 of the PR

Mark these keys as obsolete in Weblate. Remove them from all catalogs after
release; older app versions may still use them.

Keep the current `common` and `home` namespaces.

## Namespace `common`

| Obsolete key | Replacement |
| --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `actors.you_accusativus` | Complete ICU messages |
| `actors.you_dativus` | Complete ICU messages |
| `expense_details.balance_list.are_settled_up` | `expense_details.balance_list.settled` |
| `expense_details.balance_list.is_settled_up` | `expense_details.balance_list.settled` |
| `ui.added_by` | `expense_metadata.added_by` |
| `ui.deleted_by` | `expense_metadata.deleted_by` |
| `ui.edited_by` | `expense_metadata.edited_by` |
| `ui.balance` | `balance_summary.more` (`count`) |
| `ui.balances` | `balance_summary.more` (`count`) |
| `ui.expense.for` | `activity.*_for_expense`, `expense_list.conversion_for_users` |
| `ui.expense.you.deleted` | `activity.user_deleted_expense` (`actor`) |
| `ui.expense.user.deleted` | `activity.user_deleted_expense` (`actor`) |
| `ui.expense.you.get` | `expense_participant.gets`, `balance_list.gets` |
| `ui.expense.user.get` | `expense_participant.gets`, `balance_list.gets` |
| `ui.expense.you.lent` | `expense_details.balance_list.lent`, `ui.expense.statements.you_lent*` |
| `ui.expense.user.lent` | `expense_details.balance_list.lent` (`actor`) |
| `ui.expense.you.owe` | `expense_details.balance_list.owes`, `expense_participant.owes`, `balance_summary.you_owe_friend`, `ui.expense.statements.you_owe*` |
| `ui.expense.user.owe` | `expense_details.balance_list.owes`, `expense_participant.owes`, `balance_summary.friend_owes_you` |
| `ui.expense.you.pay` | `balance_list.pays`, `ui.transfer`, `ui.expense.statements.you_pay_user` |
| `ui.expense.user.pay` | `balance_list.pays`, `ui.transfer`, `ui.expense.statements.user_pays_you`, `ui.expense.statements.user_pays_user` |
| `ui.expense.you.paid` | `expense_participant.paid` |
| `ui.expense.user.paid` | `expense_participant.paid` |
| `ui.expense.you.received` | `expense_participant.received` |
| `ui.expense.user.received` | `expense_participant.received` |

## Namespace `home`

| Obsolete key | Replacement |
| --------------------- | ----------------------------- |
| `hero.title_part1` | `hero.title_before_highlight` |
| `hero.subtitle_part1` | `hero.subtitle` |
| `hero.subtitle_link` | `hero.subtitle` |
| `hero.subtitle_part2` | `hero.subtitle` |

## Keep

All keys not listed above remain unchanged, including `actors.you`,
`ui.expense.{paid_by,received_by,from,to}`,
`ui.and`, `ui.on`, `account.messages.submit_*`, `errors.invalid_split`,
`errors.request_error`, and `errors.subscribe_error`.

## Translation notes

- Restored keys use English fallback until translated.
- Keep `errors.signin_error`; it now requires `{error}`.
- Use `{name}` for interpolation. Nested ICU braces such as
`other {{person} owes}` are valid; do not replace them globally.
- Participant messages must include `<person/>` and `<amount/>` once per branch.
They render the existing clickable user and styled amount components.
18 changes: 18 additions & 0 deletions next-i18next.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
// @ts-expect-error i18next-icu's CommonJS export has an invalid ambient module declaration.
import ICUModule from 'i18next-icu/cjs';

const ICU = ICUModule.default ?? ICUModule;

/** @param {string} lng */
const parseLngForICU = (lng) =>
'default' === lng ? 'en' : 'ca@valencia' === lng ? 'ca-ES-valencia' : lng;

/** @type {import('next-i18next').UserConfig} */
const config = {
i18n: {
Expand All @@ -22,7 +31,16 @@ const config = {
],
localeDetection: false,
},
fallbackLng: 'en',
localePath: './public/locales',
i18nFormat: {
// Keep the existing route and Weblate locale codes while ICU uses valid BCP 47 tags.
parseLngForICU,
},
onPreInitI18next: (i18n) => {
i18n.use(ICU);
},
serializeConfig: false,
};

export default config;
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@
"i18next": "^25.10.10",
"i18next-browser-languagedetector": "^8.2.1",
"i18next-http-backend": "^3.0.6",
"i18next-icu": "^2.4.1",
"input-otp": "^1.2.3",
"intl-messageformat": "^10.7.18",
"lucide-react": "^0.544.0",
"nanoid": "^5.0.6",
"next": "15.5.18",
Expand Down
66 changes: 66 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion prisma/seed-checksum.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
157cf91ec892d975f64aaf8ef567b06bdc5cfbd238a1ff3c59f92cdc4081d77f
0259523777d99a90e4fbda5a66a33f00033a1021a4eed5687f11d1899f77c125
8 changes: 4 additions & 4 deletions public/locales/cs/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
"you_dativus": "Vám"
},
"auth": {
"continue_with": "Pokračovat s {{provider}}",
"continue_with": "Pokračovat s {provider}",
"email_placeholder": "Zadejte váš email",
"no_providers_configured": "Není nastaven žádný poskytovatel přihlášení",
"no_providers_instructions": "Abyste se mohli přihlásit, nastavte prosím alespoň jednoho poskytovatele přihlášení. Pro více informací se podívejte na",
Expand Down Expand Up @@ -140,7 +140,7 @@
"group_name_update_failed": "Chyba při aktualizaci jména skupiny",
"import_failed": "Chyba při importování souboru",
"invalid_cron_expression": "Neplatný cron výraz",
"invalid_currency_code": "Neplatný kód měny {{code}}",
"invalid_currency_code": "Neplatný kód měny {code}",
"language_change_failed": "Chyba při změně jazyka",
"less_than": "Soubor by měl být menší než",
"name_required": "Musí být zadáno jméno",
Expand All @@ -153,7 +153,7 @@
"request_error": "Chyba při požadavku na notifikace",
"saving_expense": "Chyba při ukládání výdaje",
"setting_update_failed": "Nastavení se nepodařilo aktualizovat",
"signin_error": "Při přihlašování došlo k chybě: ",
"signin_error": "Při přihlašování došlo k chybě: {error}",
"signup_disabled": "Registrace nových účtů je v této instanci zakázána",
"something_went_wrong": "Něco se pokazilo",
"subscribe_error": "Nelze se přihlásit k odběru oznámení",
Expand Down Expand Up @@ -344,7 +344,7 @@
"edit_description": "Toto změní rozvrh pro budoucí výdaje. Existující výdaje upraveny nebudou.",
"edit_title": "Upravit opakování",
"empty": "Žádné výdaje zatím nejsou opakované",
"expense_for_the_amount_of": "Výdaj {{name}} za {{amount}} {{currency}}",
"expense_for_the_amount_of": "Výdaj {name} za {amount} {currency}",
"last_day": "Poslední den",
"months": "Měsíce",
"never": "Není nastaven žádný plán",
Expand Down
10 changes: 5 additions & 5 deletions public/locales/de/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
"you_dativus": "Dir"
},
"auth": {
"continue_with": "Weiter mit {{provider}}",
"continue_with": "Weiter mit {provider}",
"email_placeholder": "Mailadresse eingeben",
"no_providers_configured": "Keine Authentifizierungsanbieter konfiguriert",
"no_providers_instructions": "Bitte konfigurieren Sie mindestens einen Authentifizierungsanbieter, um sich anzumelden. Siehe die",
Expand Down Expand Up @@ -165,9 +165,9 @@
"image_compression_failed": "Bildkomprimierung fehlgeschlagen, versuche Originaldatei hochzuladen",
"import_failed": "Fehler beim Importieren der Datei",
"invalid_cron_expression": "Ungültiger Cron-Ausdruck",
"invalid_currency_code": "Ungültiger Währungscode {{code}}",
"invalid_currency_code": "Ungültiger Währungscode {code}",
"language_change_failed": "Fehler beim Ändern der Sprache",
"less_than": "Datei sollte kleiner als {{size}}MB sein",
"less_than": "Datei sollte kleiner als {size}MB sein",
"name_required": "Name ist erforderlich",
"no_providers": "Fehler beim Abrufen der Authentifizierungsanbieter. Bitte prüfen Sie die Backend-Logs.",
"notification_not_supported": "Benachrichtigungen werden nicht unterstützt",
Expand All @@ -178,7 +178,7 @@
"request_error": "Fehler bei der Anfrage der Benachrichtigung",
"saving_expense": "Fehler beim Speichern der Ausgabe",
"setting_update_failed": "Einstellung konnte nicht aktualisiert werden",
"signin_error": "Beim Anmelden ist ein Fehler aufgetreten: ",
"signin_error": "Beim Anmelden ist ein Fehler aufgetreten: {error}",
"signup_disabled": "Neuanmeldung ist in dieser Instanz deaktiviert",
"something_went_wrong": "Etwas ist schiefgelaufen",
"subscribe_error": "Fehler beim Abonnieren der Benachrichtigung",
Expand Down Expand Up @@ -377,7 +377,7 @@
"edit_description": "Dadurch ändert sich der Zeitplan für zukünftige Ausgaben. Bestehende Ausgaben werden nicht geändert.",
"edit_title": "Wiederholung bearbeiten",
"empty": "Noch keine wiederkehrenden Ausgaben",
"expense_for_the_amount_of": "Ausgabe {{name}} in Höhe von {{amount}} {{currency}}",
"expense_for_the_amount_of": "Ausgabe {name} in Höhe von {amount} {currency}",
"last_day": "Letzter Tag",
"months": "Monate",
"never": "Kein Zeitplan festgelegt",
Expand Down
2 changes: 1 addition & 1 deletion public/locales/el/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
"you_dativus": "Εσύ"
},
"auth": {
"continue_with": "Συνέχεια με {{provider}}"
"continue_with": "Συνέχεια με {provider}"
},
"expense_details": {
"add_expense": "Προσθήκη εξόδου",
Expand Down
Loading
Loading