Skip to content

feat: add Paraglide.js i18n with English/Japanese support#64

Open
nyatinte wants to merge 4 commits intomainfrom
feat/i18n
Open

feat: add Paraglide.js i18n with English/Japanese support#64
nyatinte wants to merge 4 commits intomainfrom
feat/i18n

Conversation

@nyatinte
Copy link
Copy Markdown
Owner

What

  • Add Paraglide.js v2-based i18n with English and Japanese support
  • Introduce src/i18n.ts as the single entry point for locale initialization and message exports
  • Replace all hardcoded UI strings with m.xxx() message calls
  • Decouple WorkspaceNotFoundError from its message (message-less error; localization at the catch site)
  • Add Japanese E2E tests using locale: "ja_JP.UTF-8" to verify actual Japanese output
  • Add LANG=C/POSIX unit tests to guard against Intl.Locale RangeError in minimal Unix environments

Why

Users running prw in Japanese-locale environments see English output today. Since the tool is primarily developed and used in a Japanese context, providing native Japanese output removes friction in daily use. Paraglide.js was chosen because its compiler generates JSDoc-typed JS output with zero runtime overhead, and the #paraglide/* subpath import keeps generated code out of src/.

The LANG=C guard matters because Docker containers and minimal CI images often default to LANG=C, which causes new Intl.Locale('C') to throw a RangeError, crashing the CLI before any workspace detection runs.

Ref

- Add Paraglide.js v2 compiler-based i18n (en/ja)
- Introduce src/i18n.ts as single entry point for locale init and message exports
- Replace all hardcoded UI strings with m.xxx() message calls
- Decouple WorkspaceNotFoundError from its message (localized at catch site)
- Guard against LANG=C/POSIX crashing Intl.Locale with try/catch fallback
- Add Japanese E2E tests and unit tests for non-BCP47 locales
- Add paraglide:compile prerequisite to build/check/fix/typecheck scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 15, 2026

🦋 Changeset detected

Latest commit: 14c3015

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces comprehensive internationalization capabilities to the CLI tool, enabling it to display messages in English and Japanese based on the user's system locale. This significantly improves the user experience for Japanese-speaking users and enhances the tool's resilience in diverse operating environments by addressing potential locale-related issues.

Highlights

  • Internationalization (i18n) Implementation: Integrated Paraglide.js v2 to provide i18n support, initially for English and Japanese locales, centralizing message definitions and locale initialization.
  • Decoupled Error Messages: Refactored WorkspaceNotFoundError to be message-less, allowing error messages to be localized at the catch site rather than being hardcoded within the error class.
  • UI String Localization: Replaced all hardcoded user interface strings across the application with dynamic message calls (m.xxx()) from the Paraglide.js message system.
  • Robust Locale Handling: Implemented logic to correctly initialize the locale using os-locale and gracefully fall back to the base locale for unsupported or non-BCP47 locales (e.g., LANG=C, POSIX), preventing Intl.Locale RangeError in minimal environments.
  • Enhanced Testing: Added new E2E tests to verify correct Japanese output and unit tests to ensure locale initialization handles edge cases like LANG=C environments.
Changelog
  • .gitignore
    • Added generated/ directory to be ignored by Git, which contains Paraglide.js compiled output.
  • messages/en.json
    • Added English translation messages for various UI prompts and error messages.
  • messages/ja.json
    • Added Japanese translation messages corresponding to the English messages.
  • package.json
    • Added imports field to configure module resolution for Paraglide.js generated files.
    • Updated build, check, fix, and typecheck scripts to include the paraglide:compile step.
    • Added a new paraglide:compile script for generating i18n messages.
    • Added os-locale as a dependency for detecting the operating system's locale.
    • Added @inlang/paraglide-js as a development dependency.
  • pnpm-lock.yaml
    • Updated the lockfile to reflect the addition of new dependencies and their transitive dependencies.
  • project.inlang/settings.json
    • Added a new Inlang project settings file, configuring base locale, supported locales (en, ja), and the message format plugin.
  • src/cli.ts
    • Imported internationalized messages (m) from i18n.js.
    • Replaced hardcoded UI strings for package selection, script selection, and cancellation messages with m.select_package(), m.select_script(), m.cancelled(), m.no_packages_match(), m.multiple_packages_match(), and m.no_scripts_in_package().
  • src/i18n.test.ts
    • Added a new test file to verify the initializeLocale function's behavior, including correct locale resolution and fallback for unsupported or non-BCP47 locales.
  • src/i18n.ts
    • Added a new file to centralize locale initialization logic using os-locale and to re-export Paraglide.js messages (m).
  • src/index.ts
    • Imported initializeLocale and m for internationalization.
    • Called initializeLocale() at the start of the main command execution to set the correct locale.
    • Modified error handling for WorkspaceNotFoundError to display a localized message using m.workspace_root_required().
  • src/runner.ts
    • Imported internationalized messages (m) from i18n.js.
    • Replaced the hardcoded pnpm run failure message with m.pnpm_run_failed().
  • src/ui.ts
    • Imported internationalized messages (m) from i18n.js.
    • Replaced hardcoded prompt messages with m.select_package() and m.select_script().
  • src/workspace.test.ts
    • Updated the test for findWorkspaceRoot to assert against the WorkspaceNotFoundError class directly, rather than its specific message string.
  • src/workspace.ts
    • Modified the WorkspaceNotFoundError constructor to no longer accept a message, decoupling the error from its display message.
  • test/snapshots/prw.e2e.test.ts.snap
    • Added a new snapshot for the Japanese package picker output.
  • test/prw.e2e.test.ts
    • Added a locale option to launchPrwSession to simulate different system locales.
    • Added new end-to-end tests to verify that the CLI displays Japanese messages correctly when the locale is set to Japanese.
  • tsconfig.json
    • Added allowJs: true to the compiler options.
    • Included the generated directory in the include array for TypeScript compilation.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces comprehensive internationalization support using Paraglide.js, adding translations for English and Japanese. The changes are well-executed, including the integration of Paraglide's compilation into the build process, robust locale detection with graceful fallbacks, and replacement of hardcoded UI strings with localized messages. A notable improvement is the decoupling of WorkspaceNotFoundError from its display message, enhancing maintainability. The addition of both unit and end-to-end tests to verify the new i18n logic and localized UI is excellent. I have one minor suggestion to improve code readability and type safety in the new locale initialization logic. Overall, this is a high-quality contribution that significantly improves the user experience for Japanese users.

Comment thread src/i18n.ts Outdated
Comment on lines +18 to +20
const locale = locales.includes(language as Locale)
? (language as Locale)
: baseLocale;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using find() with a nullish coalescing operator (??) can make this logic more concise and avoids the need for type assertions, which improves readability and type safety.

  const locale = locales.find((l) => l === language) ?? baseLocale;

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

os-locale v8.0.0 returns a string synchronously, not a Promise. Verified: typeof osLocale() is "string" and osLocale() instanceof Promise is false. No change needed.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0ca388dbe5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/i18n.ts
nyatinte and others added 3 commits March 15, 2026 23:59
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@nyatinte
Copy link
Copy Markdown
Owner Author

@copilot fix CI error

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 15, 2026

@nyatinte I've opened a new pull request, #68, to work on those changes. Once the pull request is ready, I'll request review from you.

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