Skip to content

UI english versions - #104

Merged
mlaszcz-cryptolab merged 10 commits into
release/v1.0.6from
UI-english-versions
Aug 13, 2026
Merged

UI english versions#104
mlaszcz-cryptolab merged 10 commits into
release/v1.0.6from
UI-english-versions

Conversation

@mlaszcz-cryptolab

Copy link
Copy Markdown
Contributor

Summary

Makes the RUNE Console fully bilingual (Korean/English) with an in-navbar language toggle. Korean copy is unchanged; English is new. Three layers of work, in three commits.

Base branch: release/v1.0.6. ~47 frontend files, +1,398/−421. No backend/Go changes.

What's in it

  1. Bilingual UI — static typed locale tables (85c50fa)
    All user-facing Korean strings moved out of components into two static, compile-time-typed TypeScript tables (src/locales/en.ts / ko.ts), read through a single L accessor. ko.ts is typed as TLocale = typeof en, so a key added to one language and missing from the other is a build error — the two can't silently drift. Every component reads L.x.y; a globe LanguageToggle lives in the navbar. Tests are pinned to Korean in test/setup.ts (the suite asserts the original copy).

  2. Brand casing standardization (dbd9141)
    Normalized all brand mentions to all-caps RUNE in the locale tables (en.ts + ko.ts), per review. Technical identifiers are unaffected.

  3. i18next live language switching — no reload flash (3e5771c)
    Replaced reload-on-switch with in-place switching:

  • Plain i18next drives language state; L becomes a Proxy over the active table, so all existing L.x.y call sites and the typed tables stay unchanged (i18next's JSON catalogs would have lost the compile-time type safety).
  • A LocaleProvider subscribes to i18next's languageChanged and remounts its subtree, so switching re-renders in place instead of window.location.reload() — removing the switch flash.
  • setLanguage calls changeLanguage (keeps localStorage persistence); LanguageToggle reads the live language via getLanguage().

  1. 이중 언어(Bilingual) UI — 정적 타입 로케일 테이블 (85c50fa)
    사용자에게 노출되는 모든 한국어 문자열을 컴포넌트에서 분리하여, 단일 L 접근자(accessor)를 통해 읽을 수 있는 두 개의 컴파일 타임 정적 타입 TypeScript 테이블(src/locales/en.ts 및 ko.ts)로 이동했습니다. ko.ts는 TLocale = typeof en으로 타입이 지정되어, 한 언어에만 키가 추가되고 다른 언어에 누락될 경우 빌드 에러가 발생합니다. 따라서 두 언어 파일 간의 싱크가 어긋나는 것을 원천적으로 방지합니다. 모든 컴포넌트는 L.x.y 형태로 문자열을 참조하며, 네비게이션 바에는 지구본 모양의 언어 전환 토글(LanguageToggle)을 추가했습니다. 테스트 환경(test/setup.ts)은 한국어로 고정하여 기존 테스트 코드들이 원본 텍스트를 정상적으로 검증할 수 있도록 했습니다.

  2. 브랜드명 대소문자 표기 표준화 (dbd9141)
    코드 리뷰 피드백을 반영하여 로케일 테이블(en.ts 및 ko.ts) 내의 모든 브랜드 명칭을 대문자 'RUNE'으로 통일했습니다. 코드 내 기술적인 식별자(변수명 등)는 영향을 받지 않습니다.

  3. i18next 실시간 언어 전환 — 새로고침 깜빡임 제거 (3e5771c)
    언어 변경 시 페이지 전체가 새로고침되던 방식을 즉시 반영(in-place switching)되도록 개선했습니다:

기본 i18next가 언어 상태를 관리하도록 구성했습니다. L 객체는 현재 활성화된 언어 테이블을 감싸는 Proxy로 동작하므로, 기존의 모든 L.x.y 호출부와 타입 정의 테이블을 수정 없이 그대로 유지할 수 있었습니다 (i18next의 기본 JSON 카탈로그 방식을 사용했다면 컴파일 타임 타입 안정성을 잃었을 것입니다).

LocaleProvider가 i18next의 languageChanged 이벤트를 구독하여 하위 트리를 리마운트(remount)합니다. 이를 통해 window.location.reload() 없이 화면이 제자리에서 리렌더링되어 언어 전환 시 발생하던 화면 깜빡임 현상이 사라졌습니다.

setLanguage 함수는 내부적으로 changeLanguage를 호출하여 로컬 스토리지(localStorage) 저장 상태를 유지하며, LanguageToggle 컴포넌트는 getLanguage()를 통해 현재 적용된 언어를 실시간으로 읽어옵니다

mlaszcz-cryptolab and others added 3 commits July 24, 2026 08:22
Move every user-visible Korean string into src/locales (ko.ts verbatim,
en.ts translated). The locale is chosen once at page load (localStorage
rc_lang override, else browser language) and exported as L; components
read plain constants — no i18n library, no runtime lookup. ko.ts is
typed against en.ts's shape so the two languages cannot drift apart
silently. Parameterized strings are per-language functions so Korean
counters and English word order each read naturally.

A globe LanguageToggle (labeled with the language it switches to) sits
in both navbars — signed-in and signed-out — and persists + reloads.

Tests are pinned to Korean in setup.ts since the suite asserts the
original copy; locales.test.ts covers the English side and structural
parity. Dev-only fixtures (UITestPage, teamsDummyData) and code
comments intentionally keep their Korean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Normalize brand 'Rune'/'rune' → 'RUNE' in the en/ko locale tables
(account-required, invite status, update notice). Technical identifiers
are unaffected (none present in the locale files).
Drive language state with plain i18next; L becomes a Proxy over the active
locale table so all L.x.y call sites and the compile-time-typed tables are
unchanged. A LocaleProvider subscribes to i18next's languageChanged and
remounts its subtree, so switching re-renders in place instead of
window.location.reload() — removing the switch flash. setLanguage calls
changeLanguage (keeps localStorage persistence); LanguageToggle reads the
live language via getLanguage(). Locale test compares L by structure since
it is now a Proxy.
CI installs with --frozen-lockfile; add the i18next entry so the lockfile
matches package.json.
@geuna0204

Copy link
Copy Markdown
Contributor

When toggling the language, things like table header text, team info change but the member status badge, button text,... don't updated. It changes after refreshing the window

Module-scope constants that captured L.* froze at the load-time language,
because LocaleProvider's key={lang} remount re-runs render but not module
top-level code. Make the shared containers resolve per-access and inline
the rest at their render sites:

- styleConstants: MEMBER/INVITATION/WORKSPACE_STATUS_VAR labels via a
  statusVar() getter helper (status badges)
- commonConstants: BTN_TEXT/MODAL_TITLES as forwarding proxies over
  L.btn/L.modal; NAV_LIST titles as getters (buttons, modal titles, nav)
- inline L.* at render sites for team-name hint, invite/delete/role/
  membership messages, username error; batchReason() helper in the drawer
Phase 1 of the i18n re-integration. release/v1.0.6 refactored the same
components this branch localized (decomposed drawers/pages into hooks+
views, unified forked modals, centralized copy into constants), so the
28 conflicts were resolved by taking release's version wholesale — the
newer architecture is the baseline. The i18n-only files (locales/en.ts,
ko.ts, index.ts, LocaleProvider, LanguageToggle) are non-conflicting and
survive. Two forked modals release deleted (teams/RemoveMembershipModal,
teams/RoleChangeConfirmModal) are dropped to match.

Phase 2 (follow-up commit) re-wires the i18n layer onto release's
centralized copy and localizes the new hook/view files. The tree is
intentionally un-localized (release Korean) at this commit.
Re-integrate the i18n layer onto release/v1.0.6's architecture, starting
with the highest-leverage surface — the centralized copy constants, which
cascade to every screen:

- mount LanguageToggle in the release Navbar; localize the workspace badge
- commonConstants: BTN_TEXT, PAGE_TITLES, MODAL_TITLES, TABLE_HEADERS,
  INPUT_LABELS, PLACEHOLDERS, ARIA_LABELS, FEEDBACK_TEXT, NAV_LIST → live
  getters/functions over L.*
- noticeConstants, errorConstants (computed-key getters), styleConstants
  (status badges via statusVar getters) → live over L.*
- teamConstants/email/username bare exports inlined at call sites (live)

All copy re-resolves on a live switch (getters/proxies), so no reload flash.
Component-level inline strings (pages, modal bodies) are the remaining pass.
tsc clean, 333/333 tests pass, build succeeds.
Complete the re-integration: every user-visible Korean string in the
components/pages now reads from the locale tables, so a live language
switch turns the entire UI English (not just the shared chrome).

- 25 files auto-localized (JSX text, attributes, string props) via the
  Korean→key reverse index from ko.ts
- interpolated strings wired to the locale's function keys (footers,
  aria-labels, confirm-dialog bodies, member-count headings, team meta,
  invite notices with the embedded status chip)
- inlined the remaining frozen module-const message captures so they
  re-resolve live (send/remove/role/delete failure copy)

Only code comments and regex character classes retain Korean. tsc clean,
333/333 tests pass, build succeeds.
The Users and Sessions filter/sort option arrays were module-scope
constants whose labels read L.* / getters — so they froze at the
load-time language and the dropdowns stayed in that language after a
live switch (the rest of the page switched, leaving the page looking
half-translated). Convert them to builder functions called in the
component body so they re-resolve on every render.

tsc clean, 333/333 tests pass, build succeeds.
The mock server seeds English sample team names (Platform, Data, …).
Add a demo-only L.demoTeams map + localizeTeamName() so those sample
names follow the language toggle on the Team Management surfaces
(tree, org chart, team card, pickers). Real, customer-created names
are not in the map and render verbatim — team names are user data and
must never be auto-translated in production; drop this map when the app
talks to a real backend.

Also aligns nav.sessions to the wireframe (세션 관리 / Session Management).
The delete-confirm tests type the displayed (localized) name. tsc clean,
333/333 tests pass, build succeeds.
@mlaszcz-cryptolab
mlaszcz-cryptolab merged commit 937cdb3 into release/v1.0.6 Aug 13, 2026
1 check passed
@jh-lee-cryptolab
jh-lee-cryptolab deleted the UI-english-versions branch August 13, 2026 07:50
jh-lee-cryptolab pushed a commit that referenced this pull request Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants