diff --git a/apps/meteor/client/providers/MeteorProvider.tsx b/apps/meteor/client/providers/MeteorProvider.tsx
index e4bd8c946e202a801a4af1ceb0f9aa9e4b19aa8f..e6896093a1d568da5e4f8da98417075ceedc2599 100644
--- a/apps/meteor/client/providers/MeteorProvider.tsx
+++ b/apps/meteor/client/providers/MeteorProvider.tsx
@@ -25,11 +25,11 @@ const MeteorProvider: FC = ({ children }) => (
 	<ConnectionStatusProvider>
 		<ServerProvider>
 			<RouterProvider>
-				<TranslationProvider>
-					<SessionProvider>
-						<TooltipProvider>
-							<ToastMessagesProvider>
-								<SettingsProvider>
+				<SettingsProvider>
+					<TranslationProvider>
+						<SessionProvider>
+							<TooltipProvider>
+								<ToastMessagesProvider>
 									<LayoutProvider>
 										<AvatarUrlProvider>
 											<CustomSoundProvider>
@@ -51,11 +51,11 @@ const MeteorProvider: FC = ({ children }) => (
 											</CustomSoundProvider>
 										</AvatarUrlProvider>
 									</LayoutProvider>
-								</SettingsProvider>
-							</ToastMessagesProvider>
-						</TooltipProvider>
-					</SessionProvider>
-				</TranslationProvider>
+								</ToastMessagesProvider>
+							</TooltipProvider>
+						</SessionProvider>
+					</TranslationProvider>
+				</SettingsProvider>
 			</RouterProvider>
 		</ServerProvider>
 	</ConnectionStatusProvider>
diff --git a/apps/meteor/client/providers/TranslationProvider.tsx b/apps/meteor/client/providers/TranslationProvider.tsx
index 711779ae52cf8fc2c2a837770b7a13afe6fc8a47..8272f6acd7bbf84e091ae7a4dc1f0fe2f2adce0a 100644
--- a/apps/meteor/client/providers/TranslationProvider.tsx
+++ b/apps/meteor/client/providers/TranslationProvider.tsx
@@ -1,5 +1,6 @@
+import { useMutableCallback } from '@rocket.chat/fuselage-hooks';
 import type { TranslationKey } from '@rocket.chat/ui-contexts';
-import { TranslationContext, useAbsoluteUrl } from '@rocket.chat/ui-contexts';
+import { useSetting, TranslationContext, useAbsoluteUrl } from '@rocket.chat/ui-contexts';
 import i18next from 'i18next';
 import I18NextHttpBackend from 'i18next-http-backend';
 import { TAPi18n, TAPi18next } from 'meteor/rocketchat:tap-i18n';
@@ -16,46 +17,105 @@ type TranslationNamespace = Extract<TranslationKey, `${string}.${string}`> exten
 		: never
 	: never;
 
-const namespaces = ['onboarding', 'registration'] as TranslationNamespace[];
+const namespacesDefault = ['onboarding', 'registration'] as TranslationNamespace[];
+
+const parseToJSON = (customTranslations: string) => {
+	try {
+		return JSON.parse(customTranslations);
+	} catch (e) {
+		return false;
+	}
+};
 
 const useI18next = (lng: string): typeof i18next => {
 	const basePath = useAbsoluteUrl()('/i18n');
 
-	const i18n = useState(() => {
+	const customTranslations = useSetting('Custom_Translations');
+
+	const parse = useMutableCallback((data: string, lngs?: string | string[], namespaces: string | string[] = []): { [key: string]: any } => {
+		const parsedCustomTranslations = typeof customTranslations === 'string' && parseToJSON(customTranslations);
+
+		const source = JSON.parse(data);
+		const result: { [key: string]: any } = {};
+
+		for (const [key, value] of Object.entries(source)) {
+			const prefix = (Array.isArray(namespaces) ? namespaces : [namespaces]).find((namespace) => key.startsWith(`${namespace}.`));
+
+			if (prefix) {
+				result[key.slice(prefix.length + 1)] = value;
+			}
+		}
+
+		if (lngs && parsedCustomTranslations) {
+			for (const language of Array.isArray(lngs) ? lngs : [lngs]) {
+				if (!parsedCustomTranslations[language]) {
+					continue;
+				}
+
+				for (const [key, value] of Object.entries(parsedCustomTranslations[language])) {
+					const prefix = (Array.isArray(namespaces) ? namespaces : [namespaces]).find((namespace) => key.startsWith(`${namespace}.`));
+
+					if (prefix) {
+						result[key.slice(prefix.length + 1)] = value;
+					}
+				}
+			}
+		}
+
+		return result;
+	});
+
+	const [i18n] = useState(() => {
 		const i18n = i18next.createInstance().use(I18NextHttpBackend).use(initReactI18next);
 
 		i18n.init({
 			lng,
 			fallbackLng: 'en',
-			ns: namespaces,
+			ns: namespacesDefault,
 			nsSeparator: '.',
+			partialBundledLanguages: true,
 			debug: false,
 			backend: {
 				loadPath: `${basePath}/{{lng}}.json`,
-				parse: (data: string, _languages?: string | string[], namespaces: string | string[] = []): { [key: string]: any } => {
-					const source = JSON.parse(data);
-					const result: { [key: string]: any } = {};
-
-					for (const key of Object.keys(source)) {
-						const prefix = (Array.isArray(namespaces) ? namespaces : [namespaces]).find((namespace) => key.startsWith(`${namespace}.`));
-
-						if (prefix) {
-							result[key.slice(prefix.length + 1)] = source[key];
-						}
-					}
-
-					return result;
-				},
+				parse,
 			},
 		});
 
 		return i18n;
-	})[0];
+	});
 
 	useEffect(() => {
 		i18n.changeLanguage(lng);
 	}, [i18n, lng]);
 
+	useEffect(() => {
+		if (!customTranslations || typeof customTranslations !== 'string') {
+			return;
+		}
+
+		const parsedCustomTranslations: Record<string, Record<string, string>> = JSON.parse(customTranslations);
+
+		for (const [ln, translations] of Object.entries(parsedCustomTranslations)) {
+			const namespaces = Object.entries(translations).reduce((acc, [key, value]): Record<string, Record<string, string>> => {
+				const namespace = key.split('.')[0];
+
+				if (namespacesDefault.includes(namespace as unknown as TranslationNamespace)) {
+					acc[namespace] = acc[namespace] ?? {};
+					acc[namespace][key] = value;
+					acc[namespace][key.slice(namespace.length + 1)] = value;
+					return acc;
+				}
+				acc.project = acc.project ?? {};
+				acc.project[key] = value;
+				return acc;
+			}, {} as Record<string, Record<string, string>>);
+
+			for (const [namespace, translations] of Object.entries(namespaces)) {
+				i18n.addResourceBundle(ln, namespace, translations);
+			}
+		}
+	}, [customTranslations, i18n]);
+
 	return i18n;
 };