added translation description & deleted french-test
authorPhiTux <redacted>
Wed, 8 Oct 2025 12:49:45 +0000 (14:49 +0200)
committerPhiTux <redacted>
Wed, 8 Oct 2025 12:49:45 +0000 (14:49 +0200)
TRANSLATION.md [new file with mode: 0644]
frontend/.prettierignore
frontend/src/i18n/flags.json
frontend/src/i18n/fr.json [deleted file]
frontend/src/routes/+layout.svelte

diff --git a/TRANSLATION.md b/TRANSLATION.md
new file mode 100644 (file)
index 0000000..fc5abcd
--- /dev/null
@@ -0,0 +1,45 @@
+# Translate DailyTxT into your language
+
+You want to help to translate DailyTxT into your language? Great! Thank you very much!  
+This document provides a description how you can help.
+
+## How to translate
+
+There are **<ins>two ways</ins>** to translate DailyTxT:
+
+1. Provide a translation by yourself and create a <ins>Pull request</ins>.
+2. Use <ins>Tolgee</ins> to provide a translation.
+
+### 1. Provide a translation by yourself and create a Pull request
+
+1. Fork the repository.
+2. You find the translation files in the folder `frontend/src/i18n/`. All strings of a language are stored in a single file!
+3. Grab some AI tool, throw 'en.json' (or any other language file) in and ask to translate it into your language (then double-check it of course). Or do it all by yourself.
+4. Save this file as `<your-language-code>.json` (e.g. `de.json` for German, `fr.json` for French, `es.json` for Spanish,...). You should only add the specific country code (like `de-CH` for Swiss-German or `fr-BE` for Belgian French) if there are significant differences in the language (try to make it as general as possible).
+5. Open the file `flags.json` in the same folder and add an entry for your language. The value of each entry (the right side) should be the emoji-flag of your country. Some browsers do not support emoji-flags, but you can find the flags on websites like this: https://flagpedia.net/emoji
+6. Open the file `frontend/src/routes/+layout.svelte`. Right at the beginning of the page (at around line 25), there are a few occurences of the supported languages. Add your language here, too. Thank you ❤️
+7. Create a Pull request.
+8. I will then publish a testing image on Docker Hub for you (named like 2.0.0-testing.1) to test your translation (and perhaps other changes too). If everything is fine, it will stay as it is and be part of the next release. Otherwise we can repeat the last steps.
+
+### 2. Use Tolgee to provide a translation
+
+> [!NOTE]  
+> I use a free account of [Tolgee](https://tolgee.io). Therefore, there is sadly a limit of 3 concurrent users (translators) per project (me included). So when you finished translating and everything is working fine, I will have to delete you from the project to make space for other translators. Sorry for that.
+
+1. Open an issue in this repository and tell me that you want to help translating DailyTxT into your language. Tell me which language you want to translate (e.g. German, French, Spanish,...). If possible, please provide a language code, that describes you language <ins>as general as possible</ins> (e.g. `de` for German, `fr` for French, `es` for Spanish,...). You should only add the specific country code (like `de-CH` for Swiss-German or `fr-BE` for Belgian French) if there are significant differences in the language.
+2. I will then send you an invitation-link to join the Tolgee project.
+3. Open the link, create a Tolgee account (if you do not have one yet) and join the project.
+4. You can now start translating! You find all strings in the project. You can filter for your language and see which strings are not translated yet.  
+<ins>Important:</ins> You have <ins>several</ins> possibilities how to use Tolgee:
+   1. You can either translate it directly in the Tolgee interface.
+   2. Or you can download the JSON-file of your language, translate it with an AI tool (or by yourself) and upload it again. (Thats pretty similar to the first way of translating, but you do not have to create a Pull request by yourself.)
+   3. Install the "Tolgee Tools" Browser Extension (Available for Firefox and Chrome-based browsers) and translate a lot of strings directly in the browser-frontend. You have to create an API-Key for that and use the URL "https://app.tolgee.io" in the Addon. Sadly several strings (e.g. inside a modal) cannot be translated with the browser extension. But you can use the extension for a lot of strings and use the Tolgee interface (Website) for the rest.
+5. When you are done, please tell me in the issue you created at the beginning.
+6. I will then publish a testing image on Docker Hub for you (named like 2.0.0-testing.1) to test your translation (and perhaps other changes too). If everything is fine, it will stay as it is and be part of the next release. Otherwise we can repeat the last steps.
+
+
+# Developer notes
+
+Check the following:
+- `frontend/src/i18n/flags.json`: Must contain an entry for the new language with the corresponding emoji-flag. See eg.: https://flagpedia.net/emoji
+- `frontend/src/routes/+layout.svelte`: Must contain an entry for the new language at around line 25.
index ab78a95ddd13952edde9aa3dd79d9718f0457051..13605c0b59c42837661b43a26b311a3ed41198ee 100644 (file)
@@ -2,3 +2,4 @@
 package-lock.json
 pnpm-lock.yaml
 yarn.lock
+*.md
\ No newline at end of file
index 3abd1b418f11eaf215b21f9727418df0774ff01b..d6df780ecc8e9a63caf6cc8ec9ea4ce32db736e5 100644 (file)
@@ -1,5 +1,4 @@
 {
   "en": "🇺🇸",
-  "de": "🇩🇪",
-  "fr": "🇫🇷"
+  "de": "🇩🇪"
 }
\ No newline at end of file
diff --git a/frontend/src/i18n/fr.json b/frontend/src/i18n/fr.json
deleted file mode 100644 (file)
index 2c7132c..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-{
-  "aLookBack": {
-    "header_X_years_ago": "{years_old, plural, one {Il y a {years_old} an} other {Il y a {years_old} ans}}",
-    "open": "Ouvrir",
-    "Year_one_letter": "A"
-  },
-  "calendar": {
-    "button_bookmark": "Marque-page",
-    "button_today": "Aujourd'hui",
-    "day_short": {
-      "friday": "Ven",
-      "monday": "Lun",
-      "saturday": "Sam",
-      "sunday": "Dim",
-      "thursday": "Jeu",
-      "tuesday": "Mar",
-      "wednesday": "Mer"
-    },
-    "toast": {
-      "error_bookmarking": "Erreur lors du marquage du jour!"
-    }
-  },
-  "export": {
-    "tags": "Tags"
-  },
-  "files": {
-    "encrypting": "Cryptage en cours...",
-    "toast": {
-      "error_deleting": "Erreur lors de la suppression d'un fichier !",
-      "error_loading": "Erreur lors du téléchargement d'un fichier !",
-      "error_saving": "Erreur lors de l'enregistrement d'un fichier !"
-    },
-    "upload": "Téléverser"
-  },
-  "log": {
-    "dropdown": {
-      "deleteDay": "Supprimer l'entrée",
-      "history": "Historique"
-    },
-    "load_images": "{amount, plural, one {# image charger} other {# images charger} }",
-    "toast": {
-      "error_deleting_day": "Erreur lors de la suppression du jour!",
-      "error_loading": "Erreur lors du chargement du texte !",
-      "error_saving": "Erreur lors de l'enregistrement du texte !"
-    },
-    "written_on": "Écrit le :"
-  },
-  "login": {
-    "alert": {
-      "empty_fields": "Les champs de saisie ne doivent pas être vides !",
-      "login_failed": "Échec de la connexion !<br />\nVeuillez vérifier les données saisies.",
-      "passwords_do_not_match": "Les mots de passe ne correspondent pas !",
-      "registration_allowed_until": "Enregistrement temporairement ouvert jusqu'à {date_and_time} (heure du serveur).",
-      "registration_failed": "Échec de l'enregistrement - veuillez analyser les messages d'erreur!",
-      "registration_failed_with_message": "Échec de l'enregistrement!<br />\nMessage d'erreur: <i>{message}</i>",
-      "registration_not_allowed": "L'enregistrement n'est pas possible actuellement!",
-      "registration_success": "Inscription réussie - veuillez vous connecter !<br/>\nEnsuite, jetez un coup d'œil aux <b><u>Paramètres</u></b> !"
-    },
-    "confirm_password": "Confirmez le mot de passe",
-    "create_account": "Créer un compte utilisateur",
-    "login": "Connexion",
-    "migration": {
-      "account_info": "Lors de la migration, les codes de secours (le cas échéant) ont été invalidés et doivent être recréés !<br/>\nEn outre, familiarisez-vous avec les nouvelles <b><u>paramètres</u></b> de votre compte !<br/><br/>\nSi tous les comptes ont été migrés sans erreur, les \"anciennes\" données peuvent être supprimées manuellement dans le panneau d'administration.",
-      "create_account": "Créer un compte utilisateur",
-      "migrate_files": "Migrer les fichiers",
-      "migrate_logs": "Migrer les entrées",
-      "migrate_templates": "Migrer les modèles",
-      "progress": "Progrès:",
-      "start_message": "La migration des données a commencé. Cela peut prendre quelques instants.",
-      "success_message": "La migration a été effectuée avec succès sans erreurs détectées ! Veuillez relancer la connexion. <br />\nEnsuite, vérifiez que toutes les données ont été migrées correctement.",
-      "warning": "Pendant ce temps, ne rechargez pas la page et ne vous reconnectez pas !"
-    },
-    "migration_completed_with_errors": "{error_count, plural, one {\"La migration s'est terminée avec {error_count} erreur détectée ! Vérifiez les journaux du serveur pour plus de détails !<br />\nSi la connexion ne fonctionne pas, ou si les données sont incorrectes, les données migrées doivent être supprimées manuellement.\"} other {\"La migration s'est terminée avec {error_count} erreurs détectées ! Vérifiez les journaux du serveur pour plus de détails !<br />\nSi la connexion ne fonctionne pas, ou si les données sont incorrectes, les données migrées doivent être supprimées manuellement.\"} }",
-    "password": "Mot de passe",
-    "toast": {
-      "account_deleted": "Compte utilisateur supprimé avec succès.",
-      "login_expired": "La session a expiré. Veuillez vous reconnecter.",
-      "login_invalid": "Authentification échouée. Veuillez vous reconnecter."
-    },
-    "username": "Nom d'utilisateur"
-  },
-  "modal": {
-    "close": "Fermer",
-    "deleteFile": {
-      "body": "Supprimer vraiment le fichier <u><b> {file}</b></u>?",
-      "delete": "Supprimer",
-      "title": "Supprimer le fichier ?"
-    }
-  },
-  "read": {
-    "load_images": "{count, plural, one {Charger # image du mois ({size})} other {Charger toutes les # images du mois ({size})} }",
-    "no_entries": "Aucune entrée"
-  },
-  "reauth": {
-    "title": "Confirmez le mot de passe"
-  },
-  "search": {
-    "description": "Avec <span>Ctrl</span> + <span>F</span>, le champ de recherche est focalisé.<br>\nVous pouvez chercher par <b>texte</b>, <b>nom de fichier</b> et <b>tags</b> :<br>\n<ul>\n  <li><b><u>Texte</u></b> : Lors de l'utilisation de plusieurs termes de recherche, les règles suivantes s'appliquent :\n    <ul>\n      <li><b>EXACT</b> : Mettez le terme de recherche complet entre <u>guillemets doubles</u> pour rechercher la séquence exacte de mots.</li>\n\t  <li><b>OU</b> : Séparez les termes de recherche avec <b>|</b> pour trouver les entrées contenant au moins un des termes.</li>\n\t  <li><b>ET</b> : Séparez les termes de recherche avec un <u>espace</u> pour trouver les entrées contenant tous les termes. L'ordre des termes est sans importance, de même que la distance entre les termes.</li>\n\t</ul>\n  </li>\n  <li><b><u>Nom de fichier</u></b> : Si le terme de recherche ne comprend qu'<u>un seul mot</u>, la recherche porte à la fois sur le texte et sur le nom du fichier.</li>\n  <li><b><u>Tags</u></b> : Le terme de recherche doit commencer par <b>#</b>. La recherche porte sur chaque entrée marquée par le tag.</li>\n</ul>",
-    "no_results": "Aucun résultat",
-    "search": "Rechercher",
-    "toast": {
-      "error": "Erreur lors de la recherche!"
-    }
-  },
-  "settings": {
-    "about": {
-      "donate": "Le DailyTxT vous plaît ? Alors, je serais ravi d'un petit don ! ❤️<br/>Le développement et la maintenance de cet outil demandent beaucoup de temps. Merci ! \uD83E\uDD70"
-    },
-    "account": "Compte utilisateur",
-    "admin": {
-      "authorized": "Accès administrateur autorisé",
-      "button_open_5_minutes": "Ouvrir pour 5 minutes",
-      "button_refresh_status": "Actualiser le statut",
-      "confirm_delete": "Supprimer le compte utilisateur vraiment ?",
-      "current_status": "Statut actuel",
-      "delete": "Supprimer",
-      "delete_account": "Supprimer le compte utilisateur",
-      "delete_warning": "Le compte utilisateur sera supprimé complètement et de manière irréversible !",
-      "environment_variables_description": "Voici les variables d'environnement définies lors du démarrage de DailyTxT. Elles se trouvent probablement dans le fichier docker-compose.",
-      "no_users": "Aucun compte utilisateur trouvé",
-      "registration": "Inscription",
-      "registration_allowed": "Autorisé",
-      "registration_allowed_until": "Enregistrement temporairement ouvert jusqu'à <strong>{date_and_time}</strong>.",
-      "registration_blocked": "Bloqué",
-      "registration_description": "La création de nouveaux comptes est actuellement désactivée par défaut (via variable d'environnement). Ce menu permet de débloquer l'enregistrement pendant 5 minutes. Ensuite, elle sera automatiquement désactivée à nouveau. La variable d'environnement reste inchangée.",
-      "registration_open_error": "Erreur lors de l'ouverture temporaire de l'enregistrement.",
-      "registration_status_error": "Erreur lors de la vérification si l'inscription est autorisée.",
-      "username": "Nom d'utilisateur",
-      "warning_delete_self": "Le compte utilisateur ne doit pas être supprimé ici, mais de préférence dans les \"paramètres\"."
-    },
-    "close": "Fermer",
-    "delete": "Supprimer",
-    "delete_account": "Supprimer le compte utilisateur",
-    "delete_account.delete_button": "Supprimer le compte utilisateur",
-    "installation_help": "Tu peux aussi installer DailyTxT comme une application. Cela se fait via les paramètres du navigateur, mais tous les navigateurs ne le prennent pas en charge. Aucune installation n'a été détectée actuellement.<br/> \n<ul>\n<li>Android : \"Ajouter à l'écran d'accueil\"</li>\n<li>Apple : \"Partager\" -> \"Sur l'écran d'accueil\"</li>\n</ul>",
-    "language": {
-      "reload_info": "Certaines modifications ne seront visibles qu'après rechargement de la page."
-    },
-    "password": {
-      "confirm_password": "Confirmez le mot de passe"
-    },
-    "reauth": {
-      "description": "Pour renforcer la sécurité, le mot de passe peut être à nouveau demandé à chaque chargement de page."
-    },
-    "statistics": {
-      "open": "Ouvrir"
-    },
-    "tags": "Tags",
-    "tags.no_tags": "Il n'existe pas encore de tags. Crée un nouveau tag en mode écriture.",
-    "timezone": {
-      "manual": "Utiliser toujours le fuseau horaire suivant pour ce compte utilisateur :"
-    }
-  },
-  "tags": {
-    "description": "Ici, tu peux ajouter et supprimer des tags pour la date sélectionnée afin de catégoriser tes entrées. Tu peux également créer de nouveaux tags ici.<br/><br/>Avec <span>Ctrl</span> + <span>G</span>, le champ de recherche est focalisé (uniquement sur le bureau).<br/><br/>Pour modifier ou supprimer complètement un tag, tu dois changer dans les paramètres",
-    "hide_selector": "Fermer la sélection des tags",
-    "input": "Étiquette...",
-    "new_tag": "Nouveau",
-    "no_tags_found": "Aucun tag trouvé...",
-    "tags": "Tags",
-    "toast": {
-      "error_adding": "Erreur lors de l'ajout du tag à la date sélectionnée !",
-      "error_removing": "Erreur lors de la suppression du tag!",
-      "error_saving": "Erreur lors de la création du tag!",
-      "error_saving_exists": "\"Le nom du tag existe déjà\""
-    }
-  },
-  "toast": {
-    "pwa": {
-      "install_button": "Installer",
-      "install_description": "Installe DailyTxT pour qu'il se comporte comme une application normale.",
-      "reload_button": "Recharger",
-      "update_available": "Une nouvelle version est disponible."
-    }
-  }
-}
\ No newline at end of file
index 2b7043fad164014f6a20b2622517352b89a6c8eb..d8d744191a372ea3ba6402a7f90b83d9b33ef321 100644 (file)
                .use(FormatIcu())
                .use(LanguageStorage())
                .init({
-                       availableLanguages: ['en', 'de', 'fr'],
+                       availableLanguages: ['en', 'de'],
                        defaultLanguage: 'en',
+                       fallbackLanguage: 'en',
                        staticData: {
                                en: () => import('../i18n/en.json'),
-                               de: () => import('../i18n/de.json'),
-                               fr: () => import('../i18n/fr.json')
+                               de: () => import('../i18n/de.json')
                        },
 
                        // for development
git clone https://git.99rst.org/PROJECT