mirror of
https://github.com/temetro/temetro.git
synced 2026-08-27 10:56:58 +00:00
frontend: add Somali, Arabic (RTL) & German languages
Add three UI locales (so/ar/de) with full ~1,660-key translations alongside en/fr, selectable in Settings → Profile. Arabic gets full right-to-left support: - config.ts registers the locales and exports a `dirFor` helper; an inline <head> script in layout.tsx sets <html dir/lang> before first paint (no RTL flash), and i18n-provider keeps them in sync on language change. - ~160 physical direction utilities converted to logical (ms/me/ps/pe/ start/end/text-start/text-end); directional chevrons/arrows get rtl:rotate-180; chat-bubble align variants fixed to logical. - IBM Plex Sans Arabic appended to the sans/heading font stacks for per-character Arabic fallback. - Language persists to the backend user_settings and re-applies on sign-in so it roams across devices (localStorage stays the offline source of truth). - New scripts/check-locales.mjs (npm run check-locales) enforces key/placeholder parity and Arabic CLDR plural completeness. Bump to 0.3.0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+30
-4
@@ -1,5 +1,5 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Geist_Mono, Inter } from "next/font/google";
|
||||
import { Geist_Mono, IBM_Plex_Sans_Arabic, Inter } from "next/font/google";
|
||||
import "./globals.css";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ThemeProvider } from "@/components/theme-provider";
|
||||
@@ -10,6 +10,27 @@ import { ToastProvider } from "@/components/ui/toast";
|
||||
const inter = Inter({ subsets: ["latin"], variable: "--font-sans" });
|
||||
const interHeading = Inter({ subsets: ["latin"], variable: "--font-heading" });
|
||||
const geistMono = Geist_Mono({ subsets: ["latin"], variable: "--font-mono" });
|
||||
// Arabic-capable fallback: Inter has no Arabic glyphs, so we append this to the
|
||||
// sans/heading stacks (see globals.css) for per-character fallback in every
|
||||
// locale, and rely on it fully when dir="rtl". Not a variable font — pin weights.
|
||||
const plexArabic = IBM_Plex_Sans_Arabic({
|
||||
subsets: ["arabic"],
|
||||
weight: ["400", "500", "600", "700"],
|
||||
variable: "--font-arabic",
|
||||
});
|
||||
|
||||
// Runs before first paint: mirror lib/i18n/config.ts `dirFor` so an Arabic user
|
||||
// gets dir="rtl" immediately instead of a flash of LTR. Detection order matches
|
||||
// i18next-browser-languagedetector (localStorage key "i18nextLng", then the
|
||||
// browser language). suppressHydrationWarning on <html> ignores the attr diff.
|
||||
const setInitialDir = `
|
||||
(function(){try{
|
||||
var l=localStorage.getItem("i18nextLng")||navigator.language||"en";
|
||||
var e=document.documentElement;
|
||||
e.lang=l;
|
||||
e.dir=l.indexOf("ar")===0?"rtl":"ltr";
|
||||
}catch(_){}})();
|
||||
`;
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "temetro — AI assistant for clinicians",
|
||||
@@ -33,17 +54,22 @@ export default function RootLayout({
|
||||
inter.variable,
|
||||
interHeading.variable,
|
||||
geistMono.variable,
|
||||
plexArabic.variable,
|
||||
"font-sans"
|
||||
)}
|
||||
>
|
||||
{/* suppressHydrationWarning: next-themes sets the theme class on <html>
|
||||
before hydration, and browser extensions (e.g. ColorZilla's
|
||||
cz-shortcut-listen) mutate <body>. Only ignores attribute diffs on
|
||||
those elements, not their children. */}
|
||||
before hydration, the dir script below sets lang/dir, and browser
|
||||
extensions (e.g. ColorZilla's cz-shortcut-listen) mutate <body>. Only
|
||||
ignores attribute diffs on those elements, not their children. */}
|
||||
<body
|
||||
className="h-dvh overflow-hidden flex flex-col"
|
||||
suppressHydrationWarning
|
||||
>
|
||||
<script
|
||||
// Sets <html dir/lang> before paint; see setInitialDir above.
|
||||
dangerouslySetInnerHTML={{ __html: setInitialDir }}
|
||||
/>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="dark"
|
||||
|
||||
Reference in New Issue
Block a user