diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index 067e085364..35e852c086 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -117,6 +117,7 @@ "after_that_well_bill_you_x_total_y_subtotal_z_tax_annually_on_date_unless_you_cancel": "", "aggregate_changed": "", "aggregate_to": "", + "agpl_licence": "", "agree": "", "agree_with_the_terms": "", "ai_assist_in_overleaf_is_included_via_writefull_groups": "", @@ -228,6 +229,7 @@ "breadcrumbs": "", "browser": "", "build_collection_of_most_used_references": "", + "built_on": "", "bullet_list": "", "buy_licenses": "", "buy_more_licenses": "", @@ -1909,6 +1911,7 @@ "sort_by": "", "sort_by_x": "", "sort_projects": "", + "source_code": "", "speak": "", "speech_input_not_available": "", "spellcheck": "", diff --git a/services/web/frontend/js/features/project-list/components/project-list-lumiere.tsx b/services/web/frontend/js/features/project-list/components/project-list-lumiere.tsx index 57a9505610..f3759217d2 100644 --- a/services/web/frontend/js/features/project-list/components/project-list-lumiere.tsx +++ b/services/web/frontend/js/features/project-list/components/project-list-lumiere.tsx @@ -99,9 +99,11 @@ const ProjectCard = memo(function ProjectCard({ }: { project: Project }) { + const { t } = useTranslation() const { tags } = useProjectListContext() const variant = getFormatVariant(project.compiler, project.quartoFlavor) - const ownerName = getOwnerName(project) + const rawOwner = getOwnerName(project) + const ownerName = rawOwner === 'You' ? t('you') : rawOwner const date = fromNowDate(project.lastUpdated) const initial = project.name.charAt(0).toUpperCase() || '?' const projectTags = tags diff --git a/services/web/frontend/js/shared/components/footer/thin-footer.tsx b/services/web/frontend/js/shared/components/footer/thin-footer.tsx index 8d44310238..414c9d3ad1 100644 --- a/services/web/frontend/js/shared/components/footer/thin-footer.tsx +++ b/services/web/frontend/js/shared/components/footer/thin-footer.tsx @@ -5,6 +5,7 @@ import type { import OLRow from '@/shared/components/ol/ol-row' import LanguagePicker from '@/shared/components/language-picker' import React from 'react' +import { useTranslation } from 'react-i18next' function FooterItemLi({ text, @@ -41,6 +42,7 @@ function Separator() { } function ThinFooter({ subdomainLang, leftItems, rightItems }: FooterMetadata) { + const { t } = useTranslation() const showLanguagePicker = Boolean( subdomainLang && Object.keys(subdomainLang).length > 1 ) @@ -62,7 +64,7 @@ function ThinFooter({ subdomainLang, leftItems, rightItems }: FooterMetadata) {
  • - Built on{' '} + {t('built_on')}{' '} - AGPL licence + {t('agpl_licence')}
  • @@ -100,7 +102,7 @@ function ThinFooter({ subdomainLang, leftItems, rightItems }: FooterMetadata) { target="_blank" rel="noopener noreferrer" > - Source code + {t('source_code')} {rightItems?.map(item => ( diff --git a/services/web/frontend/js/utils/dates.ts b/services/web/frontend/js/utils/dates.ts index b4dd84f822..000c24bd40 100644 --- a/services/web/frontend/js/utils/dates.ts +++ b/services/web/frontend/js/utils/dates.ts @@ -1,4 +1,14 @@ import moment from 'moment' +import getMeta from '@/utils/meta' + +// Set moment's display locale to match the app language so that +// fromNow() returns "il y a 2 jours" rather than "2 days ago", etc. +const _lang = getMeta('ol-i18n')?.currentLangCode ?? 'en' +if (_lang !== 'en') { + import(`moment/locale/${_lang}`) + .then(() => { moment.locale(_lang) }) + .catch(() => { /* fall back to English */ }) +} export function formatDate(date: moment.MomentInput, format?: string) { if (!date) return 'N/A' diff --git a/services/web/locales/de.json b/services/web/locales/de.json index a9559c5784..f5b6da741b 100644 --- a/services/web/locales/de.json +++ b/services/web/locales/de.json @@ -146,6 +146,7 @@ "after_that_well_bill_you_x_total_y_subtotal_z_tax_annually_on_date_unless_you_cancel": "Danach berechnen wir dir jährlich am __date__ __totalAmount__ (__subtotalAmount__ + __taxAmount__ Steuern), falls du nicht kündigst.", "aggregate_changed": "Geändert", "aggregate_to": "zu", + "agpl_licence": "AGPL-Lizenz", "agree": "Zustimmen", "agree_with_the_terms": "Ich stimme den Verso Bedingungen zu", "ai_allowance": "KI-Zulage", @@ -311,6 +312,7 @@ "browser": "Browser", "build_collection_of_most_used_references": "Erstellen Sie in der Bibliothek eine Sammlung Ihrer am häufigsten verwendeten Referenzen, damit Sie sie problemlos zu jedem Projekt hinzufügen können.", "built_in": "Eigener", + "built_on": "Basiert auf", "bullet_list": "Bullet-Liste", "buy_add_on": "Add-on kaufen", "buy_licenses": "Lizenzen kaufen", @@ -2495,6 +2497,7 @@ "sort_by_x": "Nach __x__ sortieren", "sort_projects": "Projekte sortieren", "source": "Quelldateien", + "source_code": "Quellcode", "speak": "Sprich", "speech_input_not_available": "Die Spracheingabe ist in diesem Browser noch nicht verfügbar", "spellcheck": "Rechtschreibprüfung", diff --git a/services/web/locales/en.json b/services/web/locales/en.json index 48f4a9cd85..9d7751afcf 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -143,6 +143,7 @@ "after_that_well_bill_you_x_total_y_subtotal_z_tax_annually_on_date_unless_you_cancel": "After that, we’ll bill you __totalAmount__ (__subtotalAmount__ + __taxAmount__ tax) annually on __date__, unless you cancel.", "aggregate_changed": "Changed", "aggregate_to": "to", + "agpl_licence": "AGPL licence", "agree": "Agree", "agree_with_the_terms": "I agree with the Verso terms", "ai_allowance": "AI allowance", @@ -305,6 +306,7 @@ "browser": "Browser", "build_collection_of_most_used_references": "Build a collection of your most-used references in the Library, so you can easily add them to any project.", "built_in": "Built-In", + "built_on": "Built on", "bullet_list": "Bullet list", "buy_add_on": "Buy add-on", "buy_licenses": "Buy licenses", @@ -2474,6 +2476,7 @@ "sort_by_x": "Sort by __x__", "sort_projects": "Sort projects", "source": "Source", + "source_code": "Source code", "speak": "Speak", "speech_input_not_available": "Speech input is not yet available in this browser", "spellcheck": "Spellcheck", diff --git a/services/web/locales/es.json b/services/web/locales/es.json index 3c507bf6ab..6abbf0984c 100644 --- a/services/web/locales/es.json +++ b/services/web/locales/es.json @@ -143,6 +143,7 @@ "after_that_well_bill_you_x_total_y_subtotal_z_tax_annually_on_date_unless_you_cancel": "Después de eso, le facturaremos __totalAmount__ (__subtotalAmount__ + __taxAmount__ impuestos) anualmente el __date__, a menos que cancele.", "aggregate_changed": "Cambiado", "aggregate_to": "a", + "agpl_licence": "Licencia AGPL", "agree": "De acuerdo", "agree_with_the_terms": "Estoy de acuerdo con los términos Verso", "ai_allowance": "subsidio de IA", @@ -306,6 +307,7 @@ "browser": "Navegador", "build_collection_of_most_used_references": "Cree una colección de sus referencias más utilizadas en la Biblioteca, para que pueda agregarlas fácilmente a cualquier proyecto.", "built_in": "Integrado", + "built_on": "Desarrollado con", "bullet_list": "lista de viñetas", "buy_add_on": "Comprar complemento", "buy_licenses": "Comprar licencias", @@ -2475,6 +2477,7 @@ "sort_by_x": "Ordenar por __x__", "sort_projects": "Ordenar proyectos", "source": "Fuente", + "source_code": "Código fuente", "speak": "hablar", "speech_input_not_available": "La entrada de voz aún no está disponible en este navegador", "spellcheck": "corrector ortográfico", diff --git a/services/web/locales/fr.json b/services/web/locales/fr.json index c27b6c9019..6d355b346d 100644 --- a/services/web/locales/fr.json +++ b/services/web/locales/fr.json @@ -143,6 +143,7 @@ "after_that_well_bill_you_x_total_y_subtotal_z_tax_annually_on_date_unless_you_cancel": "Après cela, nous vous facturerons __totalAmount__ (__subtotalAmount__ + __taxAmount__ taxe) annuellement le __date__, sauf si vous annulez.", "aggregate_changed": "Modification de", "aggregate_to": "en", + "agpl_licence": "Licence AGPL", "agree": "D'accord", "agree_with_the_terms": "J'accepte les conditions d'utilisation de Verso", "ai_allowance": "Allocation IA", @@ -306,6 +307,7 @@ "browser": "Navigateur", "build_collection_of_most_used_references": "Créez une collection de vos références les plus utilisées dans la bibliothèque, afin de pouvoir les ajouter facilement à n'importe quel projet.", "built_in": "Intégré", + "built_on": "Construit sur", "bullet_list": "Liste à puces", "buy_add_on": "Acheter un module complémentaire", "buy_licenses": "Acheter des licences", @@ -2479,6 +2481,7 @@ "sort_by_x": "Trier par __x__", "sort_projects": "Trier les projets", "source": "Code source", + "source_code": "Code source", "speak": "Parler", "speech_input_not_available": "La saisie vocale n'est pas encore disponible dans ce navigateur", "spellcheck": "Vérification orthographique", diff --git a/services/web/locales/it.json b/services/web/locales/it.json index a0ab6914ed..41674df02a 100644 --- a/services/web/locales/it.json +++ b/services/web/locales/it.json @@ -143,6 +143,7 @@ "after_that_well_bill_you_x_total_y_subtotal_z_tax_annually_on_date_unless_you_cancel": "Successivamente, ti addebiteremo __totalAmount__ (__subtotalAmount__ + __taxAmount__ tasse) annualmente il __date__, a meno che tu non annulli l'abbonamento.", "aggregate_changed": "Cambiato", "aggregate_to": "a", + "agpl_licence": "Licenza AGPL", "agree": "D'accordo", "agree_with_the_terms": "Sono d'accordo con i termini di Verso", "ai_allowance": "Indennità AI", @@ -305,6 +306,7 @@ "browser": "Navigatore", "build_collection_of_most_used_references": "Crea una raccolta dei riferimenti più utilizzati nella Libreria, in modo da poterli aggiungere facilmente a qualsiasi progetto.", "built_in": "Built-In", + "built_on": "Basato su", "bullet_list": "Elenco puntato", "buy_add_on": "Acquista il componente aggiuntivo", "buy_licenses": "Acquista licenze", @@ -2474,6 +2476,7 @@ "sort_by_x": "Ordina per __x__", "sort_projects": "Ordina progetti", "source": "Sorgente", + "source_code": "Codice sorgente", "speak": "Parla", "speech_input_not_available": "L'input vocale non è ancora disponibile in questo browser", "spellcheck": "Controllo ortografico",