docs(reference): import Dune: Awakening server-manager references
Phase 2 references for the host-agent Dune adapter, moved out of volatile /tmp
into docs/reference-repos/ (per Commander). Three upstream projects, .git +
node_modules + compiled binaries stripped (16MB source). Nested AI-instruction
files (.claude/, CLAUDE.md) removed so they don't pollute Corrosion sessions.
- icehunter/ dune-admin (Go+React) — 4 control planes; SETUP_DOCKER.md is the
closest analog to our agent's Dune docker control plane (compose
lifecycle, docker logs, RabbitMQ-via-exec, dune Postgres schema)
- adainrivers/ Rust/Tauri desktop — SSH+k8s BattleGroup control, maintenance
daemon, in-game admin console (Rust idiom reference)
- the4rchangel/ Node web UI replacing battlegroup.bat — matches the Commander's
Hyper-V self-host path + game-config schema
See docs/reference-repos/README.md for the full index + how we use each.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
11
docs/reference-repos/icehunter/web/src/i18n/i18n.d.ts
vendored
Normal file
11
docs/reference-repos/icehunter/web/src/i18n/i18n.d.ts
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import 'i18next'
|
||||
import type enUS from '../locales/en-US/translation.json'
|
||||
|
||||
declare module 'i18next' {
|
||||
interface CustomTypeOptions {
|
||||
defaultNS: 'translation'
|
||||
resources: {
|
||||
translation: typeof enUS
|
||||
}
|
||||
}
|
||||
}
|
||||
54
docs/reference-repos/icehunter/web/src/i18n/i18n.test.ts
Normal file
54
docs/reference-repos/icehunter/web/src/i18n/i18n.test.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import enUS from '../locales/en-US/translation.json'
|
||||
import de from '../locales/de/translation.json'
|
||||
import fr from '../locales/fr/translation.json'
|
||||
import es from '../locales/es/translation.json'
|
||||
import ptBR from '../locales/pt-BR/translation.json'
|
||||
import ru from '../locales/ru/translation.json'
|
||||
import pl from '../locales/pl/translation.json'
|
||||
import tr from '../locales/tr/translation.json'
|
||||
import zhCN from '../locales/zh-CN/translation.json'
|
||||
import ja from '../locales/ja/translation.json'
|
||||
|
||||
const LOCALES: Record<string, Record<string, unknown>> = {
|
||||
de,
|
||||
fr,
|
||||
es,
|
||||
'pt-BR': ptBR,
|
||||
ru,
|
||||
pl,
|
||||
tr,
|
||||
'zh-CN': zhCN,
|
||||
ja,
|
||||
}
|
||||
|
||||
function flatKeys(obj: Record<string, unknown>, prefix = ''): string[] {
|
||||
return Object.entries(obj).flatMap(([k, v]) => {
|
||||
const key = prefix ? `${prefix}.${k}` : k
|
||||
return typeof v === 'object' && v !== null
|
||||
? flatKeys(v as Record<string, unknown>, key)
|
||||
: [key]
|
||||
})
|
||||
}
|
||||
|
||||
describe('i18n completeness', () => {
|
||||
const enKeys = flatKeys(enUS as Record<string, unknown>)
|
||||
|
||||
it('en-US has no empty values', () => {
|
||||
enKeys.forEach((key) => {
|
||||
const parts = key.split('.')
|
||||
let val: unknown = enUS
|
||||
for (const p of parts) val = (val as Record<string, unknown>)[p]
|
||||
expect(typeof val === 'string' && val.length > 0, `en-US key "${key}" is empty`).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
Object.entries(LOCALES).forEach(([locale, translations]) => {
|
||||
it(`${locale} has all en-US keys`, () => {
|
||||
const localeKeys = new Set(flatKeys(translations))
|
||||
enKeys.forEach((key) => {
|
||||
expect(localeKeys.has(key), `${locale} missing key "${key}"`).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
58
docs/reference-repos/icehunter/web/src/i18n/index.ts
Normal file
58
docs/reference-repos/icehunter/web/src/i18n/index.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import i18n from 'i18next'
|
||||
import { initReactI18next } from 'react-i18next'
|
||||
|
||||
import enUS from '../locales/en-US/translation.json'
|
||||
import de from '../locales/de/translation.json'
|
||||
import fr from '../locales/fr/translation.json'
|
||||
import es from '../locales/es/translation.json'
|
||||
import ptBR from '../locales/pt-BR/translation.json'
|
||||
import ru from '../locales/ru/translation.json'
|
||||
import pl from '../locales/pl/translation.json'
|
||||
import tr from '../locales/tr/translation.json'
|
||||
import zhCN from '../locales/zh-CN/translation.json'
|
||||
import ja from '../locales/ja/translation.json'
|
||||
|
||||
export const LOCALE_KEY = 'dune_admin_locale'
|
||||
export const DEFAULT_LOCALE = 'en-US'
|
||||
|
||||
export const LANGUAGES = [
|
||||
{ code: 'en-US', label: 'English', flag: '🇨🇦' },
|
||||
{ code: 'de', label: 'Deutsch', flag: '🇩🇪' },
|
||||
{ code: 'fr', label: 'Français', flag: '🇫🇷' },
|
||||
{ code: 'es', label: 'Español', flag: '🇪🇸' },
|
||||
{ code: 'pt-BR', label: 'Português (BR)', flag: '🇧🇷' },
|
||||
{ code: 'ru', label: 'Русский', flag: '🇷🇺' },
|
||||
{ code: 'pl', label: 'Polski', flag: '🇵🇱' },
|
||||
{ code: 'tr', label: 'Türkçe', flag: '🇹🇷' },
|
||||
{ code: 'zh-CN', label: '中文 (简体)', flag: '🇨🇳' },
|
||||
{ code: 'ja', label: '日本語', flag: '🇯🇵' },
|
||||
] as const
|
||||
|
||||
const saved = localStorage.getItem(LOCALE_KEY) ?? DEFAULT_LOCALE
|
||||
|
||||
i18n
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
resources: {
|
||||
'en-US': { translation: enUS },
|
||||
'de': { translation: de },
|
||||
'fr': { translation: fr },
|
||||
'es': { translation: es },
|
||||
'pt-BR': { translation: ptBR },
|
||||
'ru': { translation: ru },
|
||||
'pl': { translation: pl },
|
||||
'tr': { translation: tr },
|
||||
'zh-CN': { translation: zhCN },
|
||||
'ja': { translation: ja },
|
||||
},
|
||||
lng: saved,
|
||||
fallbackLng: DEFAULT_LOCALE,
|
||||
interpolation: { escapeValue: false },
|
||||
})
|
||||
|
||||
export function setLocale(code: string): void {
|
||||
localStorage.setItem(LOCALE_KEY, code)
|
||||
void i18n.changeLanguage(code)
|
||||
}
|
||||
|
||||
export default i18n
|
||||
Reference in New Issue
Block a user