From: PhiTux Date: Sun, 17 Aug 2025 22:05:05 +0000 (+0200) Subject: integrated i18n-support with tolgee X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=0377680340166be27fcb9db563e0181ad0cc53e1;p=DailyTxT.git integrated i18n-support with tolgee --- diff --git a/backend/handlers/users.go b/backend/handlers/users.go index 7582c02..cc98457 100644 --- a/backend/handlers/users.go +++ b/backend/handlers/users.go @@ -426,6 +426,8 @@ func GetDefaultSettings() map[string]any { "aLookBackYears": []int{1, 5, 10}, "useBrowserTimezone": true, "timezone": "UTC", + "useBrowserLanguage": true, + "language": "en", } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e8ceccf..ba16482 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,6 +10,8 @@ "dependencies": { "@fortawesome/free-solid-svg-icons": "^6.7.2", "@popperjs/core": "^2.11.8", + "@tolgee/format-icu": "^6.2.7", + "@tolgee/svelte": "^6.2.7", "axios": "^1.7.8", "bootstrap": "^5.3.3", "dayjs": "^1.11.13", @@ -1158,6 +1160,39 @@ "vite": "^5.0.0" } }, + "node_modules/@tolgee/core": { + "version": "6.2.7", + "resolved": "https://registry.npmjs.org/@tolgee/core/-/core-6.2.7.tgz", + "integrity": "sha512-0Au+m9R23/gmeaLJY0X6lKcR2LSy9dW7hEFrpFvPdJoGvxc8XCNZpKlgnm1N534CwmtIBJ4rzOK6vOrSKbl45w==", + "license": "MIT" + }, + "node_modules/@tolgee/format-icu": { + "version": "6.2.7", + "resolved": "https://registry.npmjs.org/@tolgee/format-icu/-/format-icu-6.2.7.tgz", + "integrity": "sha512-rLa8EZZVX3pDYC3I6HLnLvTgwLr2PAyOw+7SanS7d7SXp9cvcxbX8O6nqHubv6K7YDqVblcj9FoFbvGBQ22PgQ==", + "license": "MIT" + }, + "node_modules/@tolgee/svelte": { + "version": "6.2.7", + "resolved": "https://registry.npmjs.org/@tolgee/svelte/-/svelte-6.2.7.tgz", + "integrity": "sha512-R7J3XO3g5BtUnXwvzljajRAnJeFIPB0qmisEl896L4IJUMHfsddDytaFRP90hlQzEgwRICMtbr43T6XFgSNJrQ==", + "license": "MIT", + "dependencies": { + "@tolgee/web": "6.2.7" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/@tolgee/web": { + "version": "6.2.7", + "resolved": "https://registry.npmjs.org/@tolgee/web/-/web-6.2.7.tgz", + "integrity": "sha512-MAgHGkL5RYREwAjUansJt98fCuQFV4uDfP11NLOCHan2Hx9rpuszv88eXX7enq9CE8eS/Ed2pELiSwb5rlYiKg==", + "license": "BSD-3-Clause", + "dependencies": { + "@tolgee/core": "6.2.7" + } + }, "node_modules/@types/bootstrap": { "version": "5.2.10", "resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-5.2.10.tgz", diff --git a/frontend/package.json b/frontend/package.json index 61ef0b5..582f257 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -34,6 +34,8 @@ "dependencies": { "@fortawesome/free-solid-svg-icons": "^6.7.2", "@popperjs/core": "^2.11.8", + "@tolgee/format-icu": "^6.2.7", + "@tolgee/svelte": "^6.2.7", "axios": "^1.7.8", "bootstrap": "^5.3.3", "dayjs": "^1.11.13", diff --git a/frontend/src/i18n/flags.json b/frontend/src/i18n/flags.json new file mode 100644 index 0000000..3abd1b4 --- /dev/null +++ b/frontend/src/i18n/flags.json @@ -0,0 +1,5 @@ +{ + "en": "🇺🇸", + "de": "🇩🇪", + "fr": "🇫🇷" +} \ No newline at end of file diff --git a/frontend/src/lib/Datepicker.svelte b/frontend/src/lib/Datepicker.svelte index 2d510d0..d205d5a 100644 --- a/frontend/src/lib/Datepicker.svelte +++ b/frontend/src/lib/Datepicker.svelte @@ -4,6 +4,9 @@ import { fly } from 'svelte/transition'; import * as bootstrap from 'bootstrap'; import { offcanvasIsOpen, sameDate } from '$lib/helpers.js'; + import { getTranslate } from '@tolgee/svelte'; + + const { t } = getTranslate(); let { bookmarkDay } = $props(); @@ -205,7 +208,7 @@ month: new Date().getMonth() + 1, year: new Date().getFullYear() }; - }}>Heute{$t('calendar.button_today')}
diff --git a/frontend/src/lib/helpers.js b/frontend/src/lib/helpers.js index 086fa6d..a453295 100644 --- a/frontend/src/lib/helpers.js +++ b/frontend/src/lib/helpers.js @@ -1,4 +1,5 @@ import {writable} from 'svelte/store'; +import json from '../i18n/flags.json'; function formatBytes(bytes) { if (!+bytes) return '0 Bytes'; @@ -20,7 +21,11 @@ function sameDate(date1, date2) { ); } -export { formatBytes, sameDate }; +function loadFlagEmoji(language) { + return json[language] || ''; +} + +export { formatBytes, sameDate, loadFlagEmoji }; export let alwaysShowSidenav = writable(true); diff --git a/frontend/src/routes/(authed)/+layout.svelte b/frontend/src/routes/(authed)/+layout.svelte index e4a35f3..5896330 100644 --- a/frontend/src/routes/(authed)/+layout.svelte +++ b/frontend/src/routes/(authed)/+layout.svelte @@ -14,7 +14,7 @@ import { API_URL } from '$lib/APIurl.js'; import { tags } from '$lib/tagStore.js'; import TagModal from '$lib/TagModal.svelte'; - import { alwaysShowSidenav } from '$lib/helpers.js'; + import { alwaysShowSidenav, loadFlagEmoji } from '$lib/helpers.js'; import { templates } from '$lib/templateStore'; import { faRightFromBracket, @@ -31,6 +31,10 @@ import axios from 'axios'; import { page } from '$app/state'; import { blur, slide, fade } from 'svelte/transition'; + import { T, getTranslate, getTolgee } from '@tolgee/svelte'; + + const { t } = getTranslate(); + const tolgee = getTolgee(['language']); let { children } = $props(); let inDuration = 150; @@ -125,6 +129,7 @@ .then((response) => { $settings = response.data; aLookBackYears = $settings.aLookBackYears.toString(); + updateLanguage(); }) .catch((error) => { console.error(error); @@ -162,6 +167,7 @@ }); }); + // check if settings have changed (special parsing of aLookBackYears needed) let settingsHaveChanged = $derived( JSON.stringify($settings) !== JSON.stringify($tempSettings) || JSON.stringify($settings.aLookBackYears) !== @@ -173,6 +179,41 @@ ) ); + function updateLanguage() { + console.log('updateLanguage()'); + if ($settings.useBrowserLanguage) { + let browserLanguage = tolgeesMatchForBrowserLanguage(); + $tolgee.changeLanguage( + browserLanguage === '' ? $tolgee.getInitialOptions().defaultLanguage : browserLanguage + ); + } else { + $tolgee.changeLanguage($settings.language); + } + } + + // Check if Tolgee contains the browser language + // returns "" if the browser language is not available + // return the language code if it is available + function tolgeesMatchForBrowserLanguage() { + const browserLanguage = window.navigator.language; + const availableLanguages = $tolgee + .getInitialOptions() + .availableLanguages.map((lang) => lang.toLowerCase()); + + // check if tolgee contains an exact match for the browser language OR a match for the first two characters (e.g., 'en' for 'en-US') + if (availableLanguages.includes(browserLanguage.toLowerCase())) { + return browserLanguage; + } + if (browserLanguage.length > 2) { + const shortBrowserLanguage = browserLanguage.slice(0, 2); + if (availableLanguages.includes(shortBrowserLanguage.toLowerCase())) { + return shortBrowserLanguage; + } + } + + return ''; + } + let isSaving = $state(false); function saveUserSettings() { if (isSaving) return; @@ -189,6 +230,9 @@ if (response.data.success) { $settings = $tempSettings; + // update language + updateLanguage(); + // show toast const toast = new bootstrap.Toast(document.getElementById('toastSuccessSaveSettings')); toast.show(); @@ -712,7 +756,7 @@