chore: kanban template
This commit is contained in:
90
apps/kanban/src/i18n/config.ts
Normal file
90
apps/kanban/src/i18n/config.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import i18n from 'i18next'
|
||||
import { initReactI18next } from 'react-i18next'
|
||||
import en from './en.json'
|
||||
|
||||
// Typed tokens: every `t('key')` is checked against en.json's shape (i18next
|
||||
// flattens it into dot-path keys), so a typo or removed key is a compile error.
|
||||
// Other locale files are loaded dynamically and are not key-checked against en;
|
||||
// a missing key falls back to the default locale at runtime.
|
||||
declare module 'i18next' {
|
||||
interface CustomTypeOptions {
|
||||
defaultNS: 'translation'
|
||||
resources: {
|
||||
translation: typeof en
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add a language: drop `i18n/<lang>.json` in this folder — Vite's
|
||||
// import.meta.glob auto-registers it below into `resources`, and
|
||||
// `supportedLocales` is derived from the files present, so no edits are needed
|
||||
// here. Content is reachable via the `/<lang>` URL prefix (e.g. `/de`, `/es`);
|
||||
// the default locale (`en`) needs no prefix.
|
||||
const localeModules = import.meta.glob('./*.json', { eager: true }) as Record<
|
||||
string,
|
||||
{ default: Record<string, unknown> }
|
||||
>
|
||||
|
||||
const resources: Record<string, { translation: Record<string, unknown> }> = {}
|
||||
for (const path in localeModules) {
|
||||
const code = path.slice(path.lastIndexOf('/') + 1).replace(/\.json$/, '')
|
||||
resources[code] = { translation: localeModules[path].default }
|
||||
}
|
||||
|
||||
export const supportedLocales = Object.keys(resources)
|
||||
export type Locale = string
|
||||
export const defaultLocale = 'en'
|
||||
|
||||
const RTL_LOCALES = new Set(['ar', 'he', 'fa', 'ur'])
|
||||
// Direction for a locale — RTL for Arabic/Hebrew/Farsi/Urdu, else LTR. Set this
|
||||
// on <html dir> at the root so the browser mirrors the layout; see the
|
||||
// pikku-rtl skill. Returns 'ltr' while the app is English-only.
|
||||
export function localeDir(locale: string = defaultLocale): 'rtl' | 'ltr' {
|
||||
return RTL_LOCALES.has(locale.split('-')[0]) ? 'rtl' : 'ltr'
|
||||
}
|
||||
|
||||
export function detectLocale(pathname: string): Locale {
|
||||
const segment = pathname.split('/')[1]
|
||||
if (supportedLocales.includes(segment as Locale)) {
|
||||
return segment as Locale
|
||||
}
|
||||
if (typeof navigator !== 'undefined') {
|
||||
const browserLang = navigator.language?.split('-')[0]
|
||||
if (supportedLocales.includes(browserLang as Locale)) {
|
||||
return browserLang as Locale
|
||||
}
|
||||
}
|
||||
return defaultLocale
|
||||
}
|
||||
|
||||
// i18n debug mode: when enabled, every *translated* string is masked to block
|
||||
// glyphs (█), so any readable text left on screen is text that never went
|
||||
// through a token — a hardcoded/inlined string. Surfaces missing i18n at a
|
||||
// glance. Toggle with `?i18n-debug` in the URL or `localStorage['i18n-debug']
|
||||
// = '1'` (or `I18N_DEBUG=1` for server-rendered builds). Off by default.
|
||||
export function isI18nDebug(): boolean {
|
||||
if (typeof process !== 'undefined' && process.env?.I18N_DEBUG === '1') return true
|
||||
if (typeof window === 'undefined') return false
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
if (params.has('i18n-debug')) return params.get('i18n-debug') !== '0'
|
||||
return window.localStorage?.getItem('i18n-debug') === '1'
|
||||
}
|
||||
|
||||
const i18nDebugPostProcessor = {
|
||||
type: 'postProcessor' as const,
|
||||
name: 'i18nDebug',
|
||||
process: (value: string) => (isI18nDebug() ? value.replace(/\S/g, '█') : value),
|
||||
}
|
||||
|
||||
i18n
|
||||
.use(initReactI18next)
|
||||
.use(i18nDebugPostProcessor)
|
||||
.init({
|
||||
resources,
|
||||
lng: typeof window !== 'undefined' ? detectLocale(window.location.pathname) : defaultLocale,
|
||||
fallbackLng: defaultLocale,
|
||||
interpolation: { escapeValue: false },
|
||||
postProcess: ['i18nDebug'],
|
||||
})
|
||||
|
||||
export default i18n
|
||||
Reference in New Issue
Block a user