Skip to content

feat(i18n): add zh-TW locale - #1893

Merged
tinsever merged 5 commits into
usekaneo:mainfrom
FunnyQ:feat/zh-tw-locale
Oct 4, 2026
Merged

tinsever merged 5 commits into
usekaneo:mainfrom
FunnyQ:feat/zh-tw-locale

Conversation

@FunnyQ

@FunnyQ FunnyQ commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

What changed?

Adds a Traditional Chinese locale, zh-TW.

  • i18n/zh-TW.json not a character conversion of zh-CN. For example, repo and token stay in English, which is how developers usually say them. and other wordings
  • The language picker showed both zh-CN and zh-TW as 「中文」, because it only looked at the zh subtag. It now adds the region only when two supported locales share a language. The other locales keep their current labels. I moved getLocaleLabel into apps/web/src/lib/i18n/get-locale-label.ts so it could have a test.
  • Auth and notification emails (magic link, OTP, password reset, notifications, workspace invitations) now use zh-TW copy for users who chose zh-TW, instead of falling back to English.
  • Rebased on main and translated the keys main added since (Home, Inbox, My tasks, sidebar), and removed the 4 keys main dropped.

Related issue

None.

How did you check it?

Checked at dev server. pnpm i18n:check zh-TW passes after the rebase.

screenshot

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Add Traditional Chinese locale and distinguish regional language options

✨ Enhancement 🐞 Bug fix 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Add a Taiwan-specific Traditional Chinese translation for the application.
• Distinguish supported locales sharing a language in the preferences picker without changing other
 labels.
• Test regional labels and uniqueness across supported locales.
Diagram

graph TD
  Preferences["Preferences picker"] --> Labels["Locale labels"] --> Intl["Intl DisplayNames"]
  Registry["Supported locales"] --> Labels
  Registry --> Loader["Locale loader"] --> Catalog["zh-TW catalog"] --> I18n["Translation runtime"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Explicit locale label map
  • ➕ Guarantees stable, distinct labels regardless of platform ICU data.
  • ➖ Requires maintaining display names for every supported locale and adding entries as locales grow.

Recommendation: Keep the Intl-based approach: it preserves existing labels for languages without siblings and scales to future regional variants. An explicit map is worth considering only if consistent labels across environments become a requirement.

Files changed (5) +3056 / -12

Enhancement (3) +3005 / -12
preferences.tsxUse shared helper in language picker +1/-12

Use shared helper in language picker

• Replaces the route-local label function with the extracted helper for both the selected language and picker options.

apps/web/src/routes/_layout/_authenticated/dashboard/settings/account/preferences.tsx

resources.tsRegister and load zh-TW +3/-0

Register and load zh-TW

• Adds zh-TW to the supported locale list and dynamically imports its catalog when selected.

i18n/resources.ts

zh-TW.jsonAdd Taiwan-specific Traditional Chinese translations +3001/-0

Add Taiwan-specific Traditional Chinese translations

• Adds a full application translation catalog using Taiwan-oriented wording, including developer terms such as Repo and Token. Includes interface, settings, task, notification, and landing-page strings.

i18n/zh-TW.json

Bug fix (1) +20 / -0
get-locale-label.tsExtract region-aware locale label helper +20/-0

Extract region-aware locale label helper

• Moves label generation into a reusable helper. It asks Intl for a regional name only when multiple supported locales share the language, retaining the locale-code fallback.

apps/web/src/lib/i18n/get-locale-label.ts

Tests (1) +31 / -0
get-locale-label.test.tsTest regional and unique locale labels +31/-0

Test regional and unique locale labels

• Adds tests for distinct English and Portuguese regional labels, an unchanged Japanese label, and uniqueness across supported locales. Mocks additional regional siblings to exercise the shared-language behavior.

apps/web/src/lib/i18n/get-locale-label.test.ts

@FunnyQ FunnyQ changed the title Feat/zh tw locale feat(i18n): add zh-TW locale Oct 2, 2026
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Taiwanese invitees get English emails ✓ Resolved
Description
getWorkspaceInvitationEmailCopy has no zh-TW entry and falls back to English instead of using
the new Traditional Chinese invitation strings. When an invitee has saved zh-TW as their locale,
invitation delivery uses English for both the subject and email body.
Code

i18n/zh-TW.json[R2613-2616]

+		"email": {
+			"subject": "{{inviterName}} 邀請你加入 Kaneo 上的 {{workspaceName}}",
+			"preview": "你受邀加入 Kaneo 上的 {{workspaceName}}",
+			"title": "加入 {{workspaceName}}",
Evidence
The new zh-TW resource contains invitation email strings, but the server-side copy resolver
handles only de, fr, ja, pt, and vi before falling back to English. Invitation delivery passes the
recipient’s saved locale to that resolver and the subject helper, so a saved zh-TW preference
selects English copy for both the subject and body.

AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points: AGENTS.md: Update Other Affected Entry Points
i18n/zh-TW.json[2613-2622]
apps/api/src/auth.ts[555-563]
apps/api/src/utils/get-workspace-invitation-email-copy.ts[1-26]
i18n/zh-TW.json[2612-2622]
apps/api/src/utils/get-workspace-invitation-email-copy.ts[1-27]
apps/api/src/auth.ts[555-575]
apps/api/src/utils/get-invitation-email-subject.ts[3-12]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Users whose saved locale is `zh-TW` receive English workspace invitations despite the new Traditional Chinese email strings because the server-side invitation copy resolver does not handle that locale.
## Fix Focus Areas
- apps/api/src/utils/get-workspace-invitation-email-copy.ts[1-27]
- i18n/zh-TW.json[2612-2622]
## Recommended Fix
Import the Traditional Chinese invitation strings and return them explicitly for `zh-TW`, preserving the existing English fallback for unsupported locales. Add a focused test covering the subject and body selected for `zh-TW`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Taiwanese users receive English sign-in mail ✓ Resolved
Description
resolveEmailLocale recognizes only English, German, Vietnamese, and Japanese, so it resolves the
newly supported zh-TW locale to English. Magic-link, verification-code, password-reset, and
notification templates all use that result when email is sent to a user with a saved zh-TW
preference.
Code

i18n/resources.ts[22]

+  "zh-TW",
Evidence
The email resolver has no Chinese locale and deterministically falls back to English. Authentication
and notification delivery pass stored locale values to templates that index their copy using this
resolver.

packages/email/src/templates/resolve-locale.ts[1-20]
packages/email/src/templates/magic-link.tsx[53-55]
packages/email/src/templates/notification.tsx[44-53]
apps/api/src/auth.ts[275-280]
apps/api/src/auth.ts[324-350]
apps/api/src/notification-preferences/delivery.ts[480-491]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The newly selectable `zh-TW` preference falls back to English throughout the transactional email templates.
## Fix Focus Areas
- packages/email/src/templates/resolve-locale.ts[1-20]
- packages/email/src/templates/magic-link.tsx[11-55]
- packages/email/src/templates/otp.tsx[11-55]
- packages/email/src/templates/password-reset.tsx[11-66]
- packages/email/src/templates/notification.tsx[17-53]
## Recommended Fix
Add `zh-TW` to email locale resolution and supply Traditional Chinese copy for each template that uses the resolver. Test that passing `zh-TW` selects that copy rather than English.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can tweak Display settings with a live preview to see your comment before it ships

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread i18n/zh-TW.json
Comment thread i18n/resources.ts
@tinsever

tinsever commented Oct 3, 2026

Copy link
Copy Markdown
Member

Thanks for adding this! The code looks good, but main has gained some new UI strings since CI ran. Testing the merge against current main shows 57 missing keys and 4 obsolete keys in zh-TW.json.

Could you update your branch from main, translate the new keys, remove the obsolete ones, and rerun pnpm i18n:check zh-TW? That’s the only blocker I found.

FunnyQ added 3 commits October 3, 2026 19:41
- Add a Traditional Chinese (Taiwan) locale written with Taiwan vocabulary,
  not a mechanical conversion of zh-CN
- Keep the key set aligned with zh-CN, using only `_other` plurals;
  `pnpm i18n:check zh-TW` passes
- Cross-check strings against ja-JP and their UI usage, e.g. `formats.never`
  labels an API key with no expiry, not an event that never happened
- Register zh-TW in supportedLocales and loadLocale, as done for ja-JP
- The language picker labelled zh-CN and zh-TW identically because only
  the language subtag was looked up
- Show the region only when several supported locales share a language
- Move getLocaleLabel out of the preferences route so it can be tested
- Test assertions depend on Node's full ICU data
- Use the zh-TW invitation strings for workspace invitation emails
- Add zh-TW copy to the magic link, OTP, password reset and notification
  templates, plus the auth email subjects
- Match the full `zh-tw` locale rather than the `zh` language code
@FunnyQ
FunnyQ force-pushed the feat/zh-tw-locale branch from 6c7b40e to 60fe5b1 Compare October 3, 2026 11:55
- Translate the 57 keys main added for Home, Inbox, My tasks and the
  sidebar, plus ticket ID errors and the task modal status error
- Remove the 4 keys main dropped: navigation.notifications,
  navigation.sidebar.overview, notifications.title and
  notifications.shortcuts.open
- Keep only `_other` plurals and the existing key order;
  `pnpm i18n:check zh-TW` passes
@FunnyQ
FunnyQ force-pushed the feat/zh-tw-locale branch from 60fe5b1 to 24d0437 Compare October 3, 2026 11:55
@FunnyQ

FunnyQ commented Oct 3, 2026

Copy link
Copy Markdown
Contributor Author

thanks for catching that
Just rebased onto main, and translated those 57 keys. pnpm i18n:check zh-TW passes now👌

@tinsever
tinsever merged commit d884f22 into usekaneo:main Oct 4, 2026
20 checks passed
adeyholar pushed a commit to adeyholar/kaneo that referenced this pull request Oct 5, 2026
### Features

- make cross-column dragged card sortable: usekaneo#1894
- **i18n:** add zh-TW locale: usekaneo#1893
- **integrations:** add label-based sync in advanced settings: usekaneo#1908

### Bug Fixes

- **web:** show the task label editor on narrow screens: usekaneo#1924
- convert ineligible contributions to draft pull requests: [291da4a](usekaneo@291da4a)
- **i18n:** translate the zh-CN strings added since the last sync: usekaneo#1916
- **ci:** exclude skipped events from eligibility concurrency: usekaneo#1917

### Credits

Huge thanks to @VictorOnwukwe, @kenny-ish, @ApplesBear-X, @tinsever, and @FunnyQ for helping!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants