Skip to content

Commit 885bb79

Browse files
Claude Code Agentclaude
andcommitted
feat: Add Japanese translations for individual pages (About, Team, Epics)
- Added 80+ new translation keys for About, Team, and Epics pages - Updated AboutPage to use translations for all content sections - Updated TeamPage to use translations for headers, labels, and messages - Updated EpicsPage to use translations for stats, filters, and empty states - Added translations for all 5 supported languages (EN, JA, ZH, AR, ES) - Added 4 new tests (test-262 through test-265) for Japanese translations Ref: #36 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent f4894ff commit 885bb79

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1856
-332
lines changed

FEATURE_REQUEST.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
# Feature Request: Issue #31
1+
# Feature Request: Issue #36
22

33
## Title
4-
[FEATURE] Add Arabic
4+
[FEATURE] translate individual pages in japanese
55

66
## Description
77
### Feature Name
88

9-
Arabic Language
9+
japanese translation on individual pages
1010

1111
### Feature Specification
1212

13-
Add Arabic as a language option
13+
japanese translation on individual pages
1414

1515
### Acceptance Criteria
1616

@@ -23,7 +23,7 @@ Small (< 1 hour)
2323

2424
## Branch
2525
All work should be committed to the `agent-runtime` branch.
26-
Commits should reference this issue: `Ref: #31`
26+
Commits should reference this issue: `Ref: #36`
2727

2828
## Mode
2929
Enhancement - Modify existing app in generated-app/

agent_state.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
2-
"session_id": "gh-issue-31-20251202-234717-19877265545",
3-
"current_issue": 31,
2+
"session_id": "gh-issue-36-20251203-072402-19885806441",
3+
"current_issue": 36,
44
"backlog_item_id": null,
55
"status": "running",
6-
"last_heartbeat": "2025-12-02T23:47:25.141711+00:00",
6+
"last_heartbeat": "2025-12-03T07:24:11.661870+00:00",
77
"restart_count": 0,
88
"working_directory": "/app/workspace/agent-runtime",
9-
"last_commit": "75c4f9dcddf3d1a30f3cc5865cd409271f09b7f0"
9+
"last_commit": "f4894ffd66e29e359fbbf7da43f1d43dde2589ab"
1010
}

generated-app/agent_state.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"desired_state": "continuous",
33
"current_state": "continuous",
4-
"timestamp": "2025-12-02T23:47:27.381Z",
4+
"timestamp": "2025-12-03T07:24:13.907Z",
55
"setBy": "agent",
66
"note": "Running in continuous mode"
77
}

generated-app/claude-progress.txt

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,76 @@
11
# Canopy - JIRA-like Project Management App
22

3-
## Project Status: ✅ COMPLETE AND VERIFIED (Issue #35 - Spanish Language)
3+
## Project Status: ✅ COMPLETE AND VERIFIED (Issue #36 - Japanese Translation on Individual Pages)
4+
5+
## Issue #36 - Japanese Translation on Individual Pages (COMPLETE)
6+
Added Japanese translations for individual pages (About, Team, Epics) that previously had hardcoded English strings.
7+
8+
### Feature Description:
9+
When users set the language to Japanese, the following pages now display fully translated content:
10+
1. **About Page** - Welcome message, mission statement, features, contribution guidelines, best practices, CTAs
11+
2. **Team Page** - Page header, stats cards, table headers, empty state, add/edit dialogs, toast messages
12+
3. **Epics Page** - Page header, stats overview, filter controls, table headers, empty state, hierarchy legend
13+
14+
### Files Modified:
15+
- src/lib/translations.ts - Added 80+ new translation keys for About, Team, and Epics pages in all 5 languages (EN, JA, ZH, AR, ES)
16+
- src/pages/AboutPage.tsx - Updated to use translations object from useApp() context instead of hardcoded strings
17+
- src/pages/TeamPage.tsx - Updated to use translations object from useApp() context instead of hardcoded strings
18+
- src/pages/EpicsPage.tsx - Updated to use translations object from useApp() context instead of hardcoded strings
19+
20+
### New Translation Keys Added:
21+
**About Page:**
22+
- welcomeToCanopy, aboutHeroDescription, ourMission, simplifyProjectManagement, missionDescription
23+
- whatMakesCanopySpecial, sprintPlanning, sprintPlanningDesc, kanbanBoard, kanbanBoardDesc
24+
- teamCollaboration, teamCollaborationDesc, customizable, customizableDesc
25+
- getInvolved, contribute, howToMakeRequests, requestsDescription
26+
- bugReports, bugReportsDesc, featureRequests, featureRequestsDesc, pullRequests, pullRequestsDesc
27+
- stepsToFollow, describeWhatHappened, includeStepsToReproduce, addScreenshotsIfPossible
28+
- explainTheFeature, shareTheUseCase, describeExpectedBehavior
29+
- forkTheRepository, makeYourChanges, submitAPr
30+
- bestPractices, beSpecificAndDescriptive, includeBrowserInfo, searchExistingIssues
31+
- oneIssuePerReport, useClearTitles, attachScreenshots
32+
- readyToGetStarted, createProjectCTA, createAProject, viewAllProjects, builtWithLove
33+
34+
**Team Page:**
35+
- teamTitle, teamDescription, addTeamMember, teamSize, totalAvailableWeeks, totalCapacityHours
36+
- member, availableWeeks, hoursPerWeek, assignedTasks, actions
37+
- noTeamMembersYet, addTeamMemberDesc, addFirstTeamMember
38+
- capacityPlanningTip, capacityPlanningTipDesc
39+
- editTeamMember, nameRequired, emailOptional, avatarColor, preview, addMember, saveChanges
40+
- teamMemberAdded, teamMemberUpdated, teamMemberRemoved
41+
- failedToAddTeamMember, failedToUpdateTeamMember, failedToRemoveTeamMember
42+
43+
**Epics Page:**
44+
- manageEpicsDesc, searchEpicsPlaceholder, filterByStatus, allStatuses, completed
45+
- issuesDone, storyPointsTotal, noChildIssues, linkIssuesToEpic
46+
- noEpicsMatchFilters, tryAdjustingFilters, epicsHelpOrganize, epicParent, projectNotFound
47+
48+
### New Tests Added (test-262 through test-265):
49+
- test-262: About page displays Japanese translations when language is set to Japanese ✅
50+
- test-263: About page contribution section displays Japanese translations ✅
51+
- test-264: Team page displays Japanese translations when language is set to Japanese ✅
52+
- test-265: Epics page displays Japanese translations when language is set to Japanese ✅
53+
54+
### E2E Tests Created:
55+
- e2e-tests/japanese-translations.spec.ts - Basic translation verification
56+
- e2e-tests/set-japanese-about.spec.ts - About page in Japanese
57+
- e2e-tests/test-263-about-contribution.spec.ts - Contribution section
58+
- e2e-tests/full-team-test.spec.ts - Team page with project creation
59+
- e2e-tests/full-epics-test.spec.ts - Epics page with project creation
60+
61+
### Build Status:
62+
- `npm run build` succeeds without errors ✅
63+
- All new tests pass (4/4) ✅
64+
- All console logs show NO_CONSOLE_ERRORS ✅
65+
- Application loads correctly ✅
66+
67+
### Screenshots Captured (Issue #36):
68+
- test-262-about-ja.png: About page with Japanese translations (hero, mission, features)
69+
- test-263-contribution.png: About page contribution section in Japanese
70+
- test-264-team.png: Team page with Japanese labels (チーム, チームサイズ, 合計稼働週数)
71+
- test-265-epics.png: Epics page with Japanese labels (エピック, 合計エピック数, すべて展開)
72+
73+
---
474

575
## Issue #35 - Spanish Language (COMPLETE)
676
Added Spanish as a language option in the Settings page.

generated-app/claude_log_20251203_072413.txt

Lines changed: 571 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
test('Create project and test Team page Japanese translations', async ({ page }) => {
4+
// First set Japanese
5+
await page.goto('http://localhost:6174/settings');
6+
await page.waitForLoadState('networkidle');
7+
await page.click('text=日本語');
8+
await page.waitForTimeout(1000);
9+
10+
// Go to projects page
11+
await page.goto('http://localhost:6174/projects');
12+
await page.waitForLoadState('networkidle');
13+
14+
// Take screenshot of projects page
15+
await page.screenshot({ path: 'screenshots/issue-36/projects-page-ja.png' });
16+
17+
// Click create project button
18+
await page.click('button:has-text("プロジェクトを作成"), a:has-text("プロジェクトを作成"), button:has-text("Create Project")');
19+
await page.waitForLoadState('networkidle');
20+
await page.waitForTimeout(500);
21+
22+
// Take screenshot of create project page
23+
await page.screenshot({ path: 'screenshots/issue-36/create-project-ja.png' });
24+
25+
// Fill in the form
26+
const nameInput = page.locator('input').first();
27+
await nameInput.fill('日本語テスト');
28+
29+
// Wait for key to auto-populate or fill it
30+
await page.waitForTimeout(500);
31+
32+
const keyInput = page.locator('input').nth(1);
33+
const keyValue = await keyInput.inputValue();
34+
if (!keyValue) {
35+
await keyInput.fill('JATEST');
36+
}
37+
38+
// Take screenshot before submit
39+
await page.screenshot({ path: 'screenshots/issue-36/create-project-filled-ja.png' });
40+
41+
// Click submit button
42+
await page.click('button[type="submit"]');
43+
await page.waitForTimeout(3000);
44+
45+
// Take screenshot after creation
46+
await page.screenshot({ path: 'screenshots/issue-36/after-create-ja.png' });
47+
48+
console.log('Current URL after create:', page.url());
49+
50+
// Get the project key from URL
51+
const url = page.url();
52+
const keyMatch = url.match(/\/projects\/([^\/]+)/);
53+
const projectKey = keyMatch ? keyMatch[1] : 'JATEST';
54+
55+
console.log('Project key:', projectKey);
56+
57+
// Navigate to team page
58+
await page.goto(`http://localhost:6174/projects/${projectKey}/team`);
59+
await page.waitForLoadState('networkidle');
60+
await page.waitForTimeout(500);
61+
62+
// Take screenshot
63+
await page.screenshot({ path: 'screenshots/issue-36/test-264-team-final.png' });
64+
65+
// Verify Japanese text
66+
const pageContent = await page.content();
67+
console.log('Team page URL:', page.url());
68+
console.log('Page contains チーム:', pageContent.includes('チーム'));
69+
console.log('Page contains チームメンバーを追加:', pageContent.includes('チームメンバーを追加'));
70+
});
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
test('Full test: Create project and view Epics page in Japanese', async ({ page }) => {
4+
// First set Japanese
5+
await page.goto('http://localhost:6174/settings');
6+
await page.waitForLoadState('networkidle');
7+
await page.click('text=日本語');
8+
await page.waitForTimeout(1000);
9+
10+
// Click "Create Project" button in sidebar
11+
await page.click('text=プロジェクトを作成');
12+
await page.waitForLoadState('networkidle');
13+
await page.waitForTimeout(500);
14+
15+
// Fill in the form - use English key to avoid encoding issues
16+
const nameInput = page.locator('input').first();
17+
await nameInput.fill('Epic Test Project');
18+
19+
await page.waitForTimeout(500);
20+
21+
// Set a simple key
22+
const keyInput = page.locator('input').nth(1);
23+
await keyInput.fill('');
24+
await keyInput.type('EPICJA', { delay: 50 });
25+
26+
await page.waitForTimeout(500);
27+
28+
// Click create/submit button
29+
await page.click('button[type="submit"]');
30+
await page.waitForTimeout(3000);
31+
32+
console.log('Current URL:', page.url());
33+
34+
// Now we should be on the project board
35+
// Click on Epics link in sidebar (エピック)
36+
await page.click('text=エピック');
37+
await page.waitForLoadState('networkidle');
38+
await page.waitForTimeout(500);
39+
40+
// Take screenshot of epics page
41+
await page.screenshot({ path: 'screenshots/issue-36/test-265-epics-success.png' });
42+
43+
// Verify Japanese text
44+
const pageContent = await page.content();
45+
console.log('Epics page URL:', page.url());
46+
console.log('Page contains エピック:', pageContent.includes('エピック'));
47+
console.log('Page contains エピックを管理し、進捗を追跡します:', pageContent.includes('エピックを管理し、進捗を追跡します'));
48+
console.log('Page contains 合計エピック数:', pageContent.includes('合計エピック数'));
49+
console.log('Page contains オープン:', pageContent.includes('オープン'));
50+
console.log('Page contains 進行中:', pageContent.includes('進行中'));
51+
console.log('Page contains 完了:', pageContent.includes('完了'));
52+
console.log('Page contains すべて展開:', pageContent.includes('すべて展開'));
53+
console.log('Page contains すべて折りたたむ:', pageContent.includes('すべて折りたたむ'));
54+
});
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
test('Full test: Create project and view Team page in Japanese', async ({ page }) => {
4+
// First set Japanese
5+
await page.goto('http://localhost:6174/settings');
6+
await page.waitForLoadState('networkidle');
7+
await page.click('text=日本語');
8+
await page.waitForTimeout(1000);
9+
10+
// Click "Create Project" button in sidebar
11+
await page.click('text=プロジェクトを作成');
12+
await page.waitForLoadState('networkidle');
13+
await page.waitForTimeout(500);
14+
15+
// Fill in the form - use English key to avoid encoding issues
16+
const nameInput = page.locator('input').first();
17+
await nameInput.fill('Test Project JA');
18+
19+
await page.waitForTimeout(500);
20+
21+
// Set a simple key
22+
const keyInput = page.locator('input').nth(1);
23+
await keyInput.fill('');
24+
await keyInput.type('TESTJA', { delay: 50 });
25+
26+
await page.waitForTimeout(500);
27+
28+
// Take screenshot before submit
29+
await page.screenshot({ path: 'screenshots/issue-36/before-create-project.png' });
30+
31+
// Click create/submit button
32+
await page.click('button[type="submit"]');
33+
await page.waitForTimeout(3000);
34+
35+
// Take screenshot after creation
36+
await page.screenshot({ path: 'screenshots/issue-36/after-project-create.png' });
37+
38+
console.log('Current URL:', page.url());
39+
40+
// Now we should be on the project board
41+
// Click on Team link in sidebar
42+
await page.click('text=チーム');
43+
await page.waitForLoadState('networkidle');
44+
await page.waitForTimeout(500);
45+
46+
// Take screenshot of team page
47+
await page.screenshot({ path: 'screenshots/issue-36/test-264-team-success.png' });
48+
49+
// Verify Japanese text
50+
const pageContent = await page.content();
51+
console.log('Team page URL:', page.url());
52+
console.log('Page contains チーム:', pageContent.includes('チーム'));
53+
console.log('Page contains チームメンバーを追加:', pageContent.includes('チームメンバーを追加'));
54+
console.log('Page contains チームサイズ:', pageContent.includes('チームサイズ'));
55+
console.log('Page contains 合計稼働週数:', pageContent.includes('合計稼働週数'));
56+
console.log('Page contains 総稼働時間:', pageContent.includes('総稼働時間'));
57+
console.log('Page contains チームメンバーがまだいません:', pageContent.includes('チームメンバーがまだいません'));
58+
});
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
// Helper to set language to Japanese
4+
async function setJapaneseLanguage(page: any) {
5+
await page.goto('http://localhost:6174/settings');
6+
await page.waitForLoadState('networkidle');
7+
// Click on Japanese option
8+
await page.click('text=日本語');
9+
await page.waitForTimeout(500);
10+
}
11+
12+
test.describe('Japanese translations on individual pages', () => {
13+
test('About page displays Japanese translations', async ({ page }) => {
14+
// First set language to Japanese
15+
await setJapaneseLanguage(page);
16+
17+
// Navigate to about page
18+
await page.goto('http://localhost:6174/about');
19+
await page.waitForLoadState('networkidle');
20+
21+
// Verify Japanese text is present
22+
await expect(page.locator('text=Canopyへようこそ')).toBeVisible({ timeout: 5000 });
23+
await expect(page.locator('text=私たちのミッション')).toBeVisible();
24+
await expect(page.locator('text=プロジェクト管理を簡素化')).toBeVisible();
25+
await expect(page.locator('text=スプリント計画')).toBeVisible();
26+
await expect(page.locator('text=カンバンボード')).toBeVisible();
27+
await expect(page.locator('text=バグ報告')).toBeVisible();
28+
await expect(page.locator('text=機能リクエスト')).toBeVisible();
29+
});
30+
31+
test('About page contribution section displays Japanese translations', async ({ page }) => {
32+
await setJapaneseLanguage(page);
33+
await page.goto('http://localhost:6174/about');
34+
await page.waitForLoadState('networkidle');
35+
36+
await expect(page.locator('text=リクエストの方法')).toBeVisible();
37+
await expect(page.locator('text=良いフィードバックのベストプラクティス')).toBeVisible();
38+
await expect(page.locator('text=始める準備はできましたか?')).toBeVisible();
39+
await expect(page.locator('text=プロジェクトを作成')).toBeVisible();
40+
});
41+
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { test, expect } from '@playwright/test';
2+
3+
test('Set Japanese and view About page', async ({ page }) => {
4+
// First go to settings
5+
await page.goto('http://localhost:6174/settings');
6+
await page.waitForLoadState('networkidle');
7+
8+
// Click on Japanese option
9+
await page.click('text=日本語');
10+
await page.waitForTimeout(1000);
11+
12+
// Take screenshot of settings with Japanese selected
13+
await page.screenshot({ path: 'screenshots/issue-36/settings-japanese.png' });
14+
15+
// Navigate to about page
16+
await page.goto('http://localhost:6174/about');
17+
await page.waitForLoadState('networkidle');
18+
await page.waitForTimeout(500);
19+
20+
// Take screenshot
21+
await page.screenshot({ path: 'screenshots/issue-36/about-japanese.png', fullPage: true });
22+
23+
// Verify Japanese text
24+
const pageContent = await page.content();
25+
console.log('Page contains Canopyへようこそ:', pageContent.includes('Canopyへようこそ'));
26+
});

0 commit comments

Comments
 (0)