feat: add user defined translations (#1756)

* feat: add user defined translations

* add refetch key for translation (#1757)

---------

Co-authored-by: Alex Christoffer Rasmussen <ac@omnivox.dk>
This commit is contained in:
Carlos Valente
2025-09-03 16:06:03 +02:00
committed by GitHub
parent ae15f3cdc5
commit 8d2d8ef979
26 changed files with 431 additions and 129 deletions
@@ -1,9 +1,11 @@
import { createContext, PropsWithChildren, useCallback, useContext } from 'react';
import { langEn, TranslationObject } from 'ontime-types';
import { postUserTranslation } from '../common/api/assets';
import { useCustomTranslation } from '../common/hooks-query/useCustomTranslation';
import useSettings from '../common/hooks-query/useSettings';
import { langDe } from './languages/de';
import { langEn } from './languages/en';
import { langEs } from './languages/es';
import { langFr } from './languages/fr';
import { langIt } from './languages/it';
@@ -21,15 +23,20 @@ const translationsList = {
export type TranslationKey = keyof typeof langEn;
interface TranslationContextValue {
userTranslation: TranslationObject;
getLocalizedString: (key: TranslationKey, lang?: string) => string;
postUserTranslation: (translation: TranslationObject) => Promise<void>;
}
const TranslationContext = createContext<TranslationContextValue>({
userTranslation: langEn,
getLocalizedString: () => '',
postUserTranslation: async () => {},
});
export const TranslationProvider = ({ children }: PropsWithChildren) => {
const { data } = useSettings();
const { data: translationData } = useCustomTranslation();
const getLocalizedString = useCallback(
(key: TranslationKey, lang = data?.language || 'en'): string => {
@@ -37,20 +44,24 @@ export const TranslationProvider = ({ children }: PropsWithChildren) => {
if (key in translationsList[lang as keyof typeof translationsList]) {
return translationsList[lang as keyof typeof translationsList][key];
}
} else if (lang === 'custom') {
return translationData[key];
}
return langEn[key];
},
[data?.language],
[data?.language, translationData],
);
const contextValue = {
userTranslation: translationData,
getLocalizedString,
postUserTranslation,
};
return <TranslationContext.Provider value={contextValue}>{children}</TranslationContext.Provider>;
};
export const useTranslation = () => {
const { getLocalizedString } = useContext(TranslationContext);
return { getLocalizedString };
const { userTranslation, getLocalizedString, postUserTranslation } = useContext(TranslationContext);
return { userTranslation, getLocalizedString, postUserTranslation };
};
+1 -1
View File
@@ -1,4 +1,4 @@
import { TranslationObject } from './en';
import { TranslationObject } from 'ontime-types';
export const langDe: TranslationObject = {
'common.expected_finish': 'Erwartetes Ende',
@@ -1,30 +0,0 @@
export const langEn = {
'common.expected_finish': 'Expected Finish',
'common.minutes': 'min',
'common.now': 'Now',
'common.next': 'Next',
'common.scheduled_start': 'Scheduled start',
'common.scheduled_end': 'Scheduled end',
'common.expected_start': 'Expected start',
'common.expected_end': 'Expected end',
'common.stage_timer': 'Stage Timer',
'common.started_at': 'Started At',
'common.time_now': 'Time now',
'common.no_data': 'No data',
'countdown.ended': 'Event ended at',
'countdown.running': 'Event running',
'countdown.select_event': 'Select an event to follow',
'countdown.to_start': 'Time to start',
'countdown.waiting': 'Waiting for event start',
'countdown.overtime': 'in overtime',
'timeline.live': 'live',
'timeline.done': 'done',
'timeline.due': 'due',
'timeline.followedby': 'Followed by',
'project.title': 'Title',
'project.description': 'Description',
'project.info': 'Project Info',
'project.url': 'Project URL',
};
export type TranslationObject = Record<keyof typeof langEn, string>;
+1 -1
View File
@@ -1,4 +1,4 @@
import { TranslationObject } from './en';
import { TranslationObject } from 'ontime-types';
export const langEs: TranslationObject = {
'common.expected_finish': 'Finalización esperada',
+1 -1
View File
@@ -1,4 +1,4 @@
import { TranslationObject } from './en';
import { TranslationObject } from 'ontime-types';
export const langFr: TranslationObject = {
'common.expected_finish': 'Fin estimée à',
+1 -1
View File
@@ -1,4 +1,4 @@
import { TranslationObject } from './en';
import { TranslationObject } from 'ontime-types';
export const langIt: TranslationObject = {
'common.expected_finish': 'Fine Prevista',
+1 -1
View File
@@ -1,4 +1,4 @@
import { TranslationObject } from './en';
import { TranslationObject } from 'ontime-types';
export const langPt: TranslationObject = {
'common.expected_finish': 'Término esperado',