From 40451970750d6b93fcd6829b55b033c3306ca1ee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Apr 2026 18:41:14 +0000 Subject: [PATCH 1/4] Initial plan From 26dbd641c6057f0a2e6c185dcd58bda2961a7b3c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Apr 2026 18:47:33 +0000 Subject: [PATCH 2/4] feat: add Korean language support and registration Agent-Logs-Url: https://github.com/Azure-Samples/DevOpsEngineerPersona/sessions/29ca39b7-971a-4aca-8545-5da6c3b00dbd Co-authored-by: dsanchezcr <10506023+dsanchezcr@users.noreply.github.com> --- e2e/app.spec.ts | 11 +++++++++-- src/lib/api.ts | 22 +++++++++++----------- src/lib/translations/README.md | 1 + src/lib/translations/index.ts | 2 ++ src/lib/translations/ko.ts | 19 +++++++++++++++++++ src/lib/types.ts | 3 ++- 6 files changed, 44 insertions(+), 14 deletions(-) create mode 100644 src/lib/translations/ko.ts diff --git a/e2e/app.spec.ts b/e2e/app.spec.ts index 81f80a4..d8907e1 100644 --- a/e2e/app.spec.ts +++ b/e2e/app.spec.ts @@ -161,7 +161,7 @@ test.describe('Core User Flows', () => { await expect(page.getByRole('button', { name: /crear nuevo juego|create new game/i })).toBeVisible() }) - test('should support multiple languages including German and Dutch', async ({ page }) => { + test('should support multiple languages including Korean, German, and Dutch', async ({ page }) => { await page.goto('/') // Verify language toggle is available (use aria-haspopup to target dropdown trigger specifically) @@ -169,7 +169,7 @@ test.describe('Core User Flows', () => { await expect(languageButton).toBeVisible() // Verify welcome description is visible (use paragraph element to avoid matching button text) - const welcomeDesc = page.locator('p').getByText(/organize|organiza|organisez|organizza|ギフト|轻松|organisieren|organiseer/i) + const welcomeDesc = page.locator('p').getByText(/organize|organiza|organisez|organizza|ギフト|쉽고 재미있게|轻松|organisieren|organiseer/i) await expect(welcomeDesc).toBeVisible() }) @@ -201,6 +201,13 @@ test.describe('Core User Flows', () => { await enPage.goto('/?lang=en') await expect(enPage.getByRole('button', { name: /create new game/i })).toBeVisible() await enContext.close() + + // Test Korean + const koContext = await browser.newContext() + const koPage = await koContext.newPage() + await koPage.goto('/?lang=ko') + await expect(koPage.getByRole('button', { name: /새 게임 만들기/i })).toBeVisible() + await koContext.close() }) test('should navigate directly to guide pages via URL parameter', async ({ page }) => { diff --git a/src/lib/api.ts b/src/lib/api.ts index 05b4500..4fc196d 100644 --- a/src/lib/api.ts +++ b/src/lib/api.ts @@ -80,7 +80,7 @@ export interface CreateGameData { organizerEmail?: string participants: Array<{ name: string; email?: string; desiredGift: string; wish: string }> sendEmails?: boolean - language?: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'zh' | 'de' | 'nl' + language?: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'ko' | 'zh' | 'de' | 'nl' } export interface CreateGameResponse extends Game { @@ -128,7 +128,7 @@ export async function updateGameAPI( code: string, action: 'requestReassignment', participantId: string, - language?: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'zh' | 'de' | 'nl' + language?: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'ko' | 'zh' | 'de' | 'nl' ): Promise { const response = await fetch(`${API_BASE_URL}/games/${code}`, { method: 'PATCH', @@ -244,7 +244,7 @@ export async function updateWishAPI( code: string, participantId: string, wish: string, - language?: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'zh' | 'de' | 'nl' + language?: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'ko' | 'zh' | 'de' | 'nl' ): Promise { const response = await fetch(`${API_BASE_URL}/games/${code}`, { method: 'PATCH', @@ -271,7 +271,7 @@ export async function updateParticipantEmailAPI( code: string, participantId: string, email: string, - language?: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'zh' | 'de' | 'nl' + language?: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'ko' | 'zh' | 'de' | 'nl' ): Promise { const response = await fetch(`${API_BASE_URL}/games/${code}`, { method: 'PATCH', @@ -332,7 +332,7 @@ export async function updateParticipantDetailsAPI( export async function confirmAssignmentAPI( code: string, participantId: string, - language?: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'zh' | 'de' | 'nl' + language?: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'ko' | 'zh' | 'de' | 'nl' ): Promise { const response = await fetch(`${API_BASE_URL}/games/${code}`, { method: 'PATCH', @@ -546,7 +546,7 @@ export interface SendEmailResponse { export async function sendOrganizerEmailAPI( code: string, organizerToken: string, - language: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'zh' | 'de' | 'nl' = 'es' + language: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'ko' | 'zh' | 'de' | 'nl' = 'es' ): Promise { const response = await fetch(`${API_BASE_URL}/email/send`, { method: 'POST', @@ -598,7 +598,7 @@ export async function sendParticipantEmailAPI( export async function sendAllParticipantEmailsAPI( code: string, organizerToken: string, - language: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'zh' | 'de' | 'nl' = 'es' + language: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'ko' | 'zh' | 'de' | 'nl' = 'es' ): Promise { const response = await fetch(`${API_BASE_URL}/email/send`, { method: 'POST', @@ -625,7 +625,7 @@ export async function sendReminderEmailAPI( code: string, organizerToken: string, participantId: string, - language: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'zh' | 'de' | 'nl' = 'es', + language: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'ko' | 'zh' | 'de' | 'nl' = 'es', customMessage?: string ): Promise { const response = await fetch(`${API_BASE_URL}/email/send`, { @@ -654,7 +654,7 @@ export async function sendReminderEmailAPI( export async function sendReminderToAllAPI( code: string, organizerToken: string, - language: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'zh' | 'de' | 'nl' = 'es', + language: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'ko' | 'zh' | 'de' | 'nl' = 'es', customMessage?: string ): Promise { const response = await fetch(`${API_BASE_URL}/email/send`, { @@ -716,7 +716,7 @@ export interface RecoverOrganizerLinkResponse { export async function recoverOrganizerLinkAPI( code: string, email: string, - language: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'zh' | 'de' | 'nl' = 'es' + language: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'ko' | 'zh' | 'de' | 'nl' = 'es' ): Promise { const response = await fetch(`${API_BASE_URL}/email/send`, { method: 'POST', @@ -750,7 +750,7 @@ export async function recoverOrganizerLinkAPI( export async function recoverParticipantLinkAPI( code: string, email: string, - language: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'zh' | 'de' | 'nl' = 'es' + language: 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'ko' | 'zh' | 'de' | 'nl' = 'es' ): Promise { const response = await fetch(`${API_BASE_URL}/email/send`, { method: 'POST', diff --git a/src/lib/translations/README.md b/src/lib/translations/README.md index fc81dd6..c19c672 100644 --- a/src/lib/translations/README.md +++ b/src/lib/translations/README.md @@ -12,6 +12,7 @@ Each language has its own file: - `fr.ts` - French (Français) - `it.ts` - Italian (Italiano) - `ja.ts` - Japanese (日本語) +- `ko.ts` - Korean (한국어) - `zh.ts` - Chinese (中文) - `de.ts` - German (Deutsch) - `nl.ts` - Dutch (Nederlands) diff --git a/src/lib/translations/index.ts b/src/lib/translations/index.ts index 7572df1..1bb4052 100644 --- a/src/lib/translations/index.ts +++ b/src/lib/translations/index.ts @@ -4,6 +4,7 @@ import { pt } from './pt' import { fr } from './fr' import { it } from './it' import { ja } from './ja' +import { ko } from './ko' import { zh } from './zh' import { de } from './de' import { nl } from './nl' @@ -15,6 +16,7 @@ export const translations = { fr, it, ja, + ko, zh, de, nl diff --git a/src/lib/translations/ko.ts b/src/lib/translations/ko.ts new file mode 100644 index 0000000..54b2218 --- /dev/null +++ b/src/lib/translations/ko.ts @@ -0,0 +1,19 @@ +import { en } from './en' + +export const ko = { + ...en, + appName: '자바 선물 교환', + welcome: '환영합니다!', + welcomeDesc: '쉽고 재미있게 선물 교환을 준비하세요', + createGame: '새 게임 만들기', + joinGame: '게임 참가하기', + enterCode: '코드를 입력하세요', + codePlaceholder: '6자리 코드', + continue: '계속', + back: '뒤로', + next: '다음', + finish: '완료', + cancel: '취소', + confirm: '확인', + language: '언어' +} diff --git a/src/lib/types.ts b/src/lib/types.ts index d457918..8e08782 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -80,7 +80,7 @@ export interface Game { archivedAt?: number // Unix timestamp in milliseconds since epoch when the game was archived (Date.now()) } -export type Language = 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'zh' | 'de' | 'nl' +export type Language = 'en' | 'es' | 'pt' | 'fr' | 'it' | 'ja' | 'ko' | 'zh' | 'de' | 'nl' export interface LanguageOption { code: Language @@ -96,6 +96,7 @@ export const LANGUAGES: LanguageOption[] = [ { code: 'fr', name: 'French', nativeName: 'Français', flag: '🇫🇷' }, { code: 'it', name: 'Italian', nativeName: 'Italiano', flag: '🇮🇹' }, { code: 'ja', name: 'Japanese', nativeName: '日本語', flag: '🇯🇵' }, + { code: 'ko', name: 'Korean', nativeName: '한국어', flag: '🇰🇷' }, { code: 'zh', name: 'Chinese', nativeName: '中文', flag: '🇨🇳' }, { code: 'de', name: 'German', nativeName: 'Deutsch', flag: '🇩🇪' }, { code: 'nl', name: 'Dutch', nativeName: 'Nederlands', flag: '🇳🇱' }, From 6c880ff00f243a7cbcfaae918da986f382dc93b6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Apr 2026 18:49:52 +0000 Subject: [PATCH 3/4] refactor: improve Korean home screen translation coverage Agent-Logs-Url: https://github.com/Azure-Samples/DevOpsEngineerPersona/sessions/29ca39b7-971a-4aca-8545-5da6c3b00dbd Co-authored-by: dsanchezcr <10506023+dsanchezcr@users.noreply.github.com> --- src/lib/translations/ko.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/lib/translations/ko.ts b/src/lib/translations/ko.ts index 54b2218..59f06af 100644 --- a/src/lib/translations/ko.ts +++ b/src/lib/translations/ko.ts @@ -15,5 +15,12 @@ export const ko = { finish: '완료', cancel: '취소', confirm: '확인', - language: '언어' + language: '언어', + darkMode: '다크 모드', + lightMode: '라이트 모드', + privacyLink: '개인정보 처리방침', + guideOrganizerLink: '주최자 가이드', + guideParticipantLink: '참가자 가이드', + guideOrganizerTitle: '주최자 가이드', + guideParticipantTitle: '참가자 가이드' } From 945a1eb66f26b265c52f3e1b3dbfb886e5f20352 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Apr 2026 18:51:02 +0000 Subject: [PATCH 4/4] fix: preserve Zava brand name in Korean translation Agent-Logs-Url: https://github.com/Azure-Samples/DevOpsEngineerPersona/sessions/29ca39b7-971a-4aca-8545-5da6c3b00dbd Co-authored-by: dsanchezcr <10506023+dsanchezcr@users.noreply.github.com> --- src/lib/translations/ko.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/translations/ko.ts b/src/lib/translations/ko.ts index 59f06af..c0642c9 100644 --- a/src/lib/translations/ko.ts +++ b/src/lib/translations/ko.ts @@ -2,7 +2,7 @@ import { en } from './en' export const ko = { ...en, - appName: '자바 선물 교환', + appName: 'Zava 선물 교환', welcome: '환영합니다!', welcomeDesc: '쉽고 재미있게 선물 교환을 준비하세요', createGame: '새 게임 만들기',