Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Internationalization Support (i18n) #242

Draft
wants to merge 5 commits into
base: develop
Choose a base branch
from

Conversation

AmitChauhan63390
Copy link
Contributor

@AmitChauhan63390 AmitChauhan63390 commented Dec 10, 2024

Summary by CodeRabbit

Release Notes

  • New Features

    • Added internationalization support with multiple language options (English, German, Spanish, Japanese, Chinese).
    • Introduced language selection in the navigation bar.
    • Implemented localized strings for user interface elements across various components (e.g., Login, Register, Main Menu, Recordings Table).
  • Bug Fixes

    • Improved consistency in string formatting across components.
  • Documentation

    • Updated localization files for German, Spanish, Japanese, and Chinese languages.
  • Chores

    • Updated dependencies for internationalization libraries.

Copy link

coderabbitai bot commented Dec 10, 2024

Walkthrough

The changes involve the integration of internationalization (i18n) capabilities into the application. This includes the addition of new dependencies in package.json related to the i18next library, the creation of localization files for multiple languages (German, English, Spanish, Japanese, and Chinese), and modifications to various components to utilize these localization features. The updates enhance user interface elements by replacing hardcoded strings with translatable keys, improving accessibility for users in different language settings.

Changes

File Change Summary
package.json Added dependencies: i18next, i18next-browser-languagedetector, i18next-http-backend, react-i18next.
public/locales/de.json New localization file for German with UI strings for login, registration, recording table, and main menu.
public/locales/en.json New localization file for English with UI strings for login, registration, recording table, and main menu.
public/locales/es.json New localization file for Spanish with UI strings for application name and login process.
public/locales/ja.json New localization file for Japanese with UI strings for login, registration, and recording functionalities.
public/locales/zh.json New localization file for Chinese with UI strings for application name and login process.
src/App.tsx Reformatted import statements and Material-UI component styles; no functional changes.
src/components/molecules/NavBar.tsx Updated import statements, added language selection state and function, modified rendering logic for language dropdown.
src/components/molecules/RecordingsTable.tsx Integrated useTranslation for localization of text labels and placeholders.
src/components/organisms/MainMenu.tsx Integrated useTranslation for localization of Tab and Button labels.
src/i18n.ts Initialized i18n instance with configurations for language detection and loading translation files.
src/index.tsx Added import statement for the i18n module.
src/pages/Login.tsx Integrated useTranslation for localization of notifications and UI labels.
src/pages/Register.tsx Integrated useTranslation for localization of notifications and UI labels.
src/components/molecules/RunsTable.tsx Integrated useTranslation for localization of column labels and other UI elements.

Poem

🐇 In a world of words so bright,
Languages dance, taking flight.
From German to Spanish, oh what a treat,
Our app now speaks, oh so sweet!
With i18next guiding the way,
Users rejoice, come what may! 🌍✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Experiment)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🧹 Outside diff range and nitpick comments (9)
src/i18n.ts (1)

11-13: Consider adding language fallback chains

While having 'en' as fallback is good, consider implementing language fallback chains for regional variants (e.g., zh-CN → zh → en).

 fallbackLng: 'en',
 debug: import.meta.env.DEV,
-supportedLngs: ['en', 'es', 'ja', 'zh','de'],
+supportedLngs: ['en', 'es', 'ja', 'zh', 'de'],
+fallbackLng: {
+  'zh-CN': ['zh', 'en'],
+  'zh-TW': ['zh', 'en'],
+  default: ['en']
+},
src/components/organisms/MainMenu.tsx (1)

18-18: Consider memoizing translation function

For performance optimization, consider memoizing the translation function if this component re-renders frequently.

-  const {t} = useTranslation();
+  const {t} = useTranslation();
+  const memoizedT = React.useCallback(t, [t]);
src/pages/Register.tsx (1)

48-52: Consider using type-safe translation keys.

To prevent runtime errors from typos in translation keys, consider using a type-safe approach with a translation key type.

Example implementation:

// src/types/i18n.ts
export type TranslationKeys = {
  register: {
    welcome_notification: string;
    error_notification: string;
    // ... other keys
  };
  // ... other namespaces
};

// Usage with type checking
const { t } = useTranslation<keyof TranslationKeys>();
src/pages/Login.tsx (2)

57-58: Remove empty language switcher comments.

The commented language switcher functionality is not implemented. Either implement the feature or remove the comments.

-   // Language switcher function
-   
-
-       {/* Language Switcher Buttons */}

Also applies to: 71-72


48-53: Consider type-safe translation approach for login translations.

Similar to the Register component, implement type-safe translation keys to prevent runtime errors.

Consider creating a shared types file for i18n keys to maintain consistency across components. This will help catch missing translations during development.

Also applies to: 91-92, 95-96, 105-106, 125-129, 132-135

src/components/molecules/NavBar.tsx (2)

183-194: Add aria-label to language selector button.

The language selector button should have an appropriate aria-label for better accessibility.

 <IconButton
   onClick={handleLangMenuOpen}
+  aria-label={t("language_selector")}
   sx={{
     display: "flex",
     alignItems: "center",
     borderRadius: "5px",
     padding: "8px",
     marginRight: "10px",
   }}
 >

254-256: Fix inconsistent language name formatting.

While other languages are displayed in their native script, "German" is written in English. Consider using "Deutsch" instead for consistency.

-German
+Deutsch
src/components/molecules/RecordingsTable.tsx (2)

67-90: Consider using an enum or constant for translation keys.

The translation keys are currently hardcoded strings. Using an enum or constant would provide better type safety and maintainability.

+export enum TranslationKeys {
+  RUN = 'recordingtable.run',
+  NAME = 'recordingtable.name',
+  SCHEDULE = 'recordingtable.schedule',
+  INTEGRATE = 'recordingtable.integrate',
+  SETTINGS = 'recordingtable.settings',
+  OPTIONS = 'recordingtable.options',
+}

 const columns: readonly Column[] = [
-  { id: 'interpret', label: t('recordingtable.run'), minWidth: 80 },
+  { id: 'interpret', label: t(TranslationKeys.RUN), minWidth: 80 },
   // ... apply to other columns
 ];

Line range hint 311-326: Group related translation keys in the modal.

The modal's translation keys follow a different pattern. Consider grouping them under a common prefix for better organization.

-<Typography variant="h6" gutterBottom>{t('recordingtable.modal.title')}</Typography>
+<Typography variant="h6" gutterBottom>{t('modal.recording.title')}</Typography>

Apply similar changes to other modal translation keys for consistency.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between b3a973f and 0772342.

📒 Files selected for processing (14)
  • package.json (3 hunks)
  • public/locales/de.json (1 hunks)
  • public/locales/en.json (1 hunks)
  • public/locales/es.json (1 hunks)
  • public/locales/ja.json (1 hunks)
  • public/locales/zh.json (1 hunks)
  • src/App.tsx (6 hunks)
  • src/components/molecules/NavBar.tsx (1 hunks)
  • src/components/molecules/RecordingsTable.tsx (10 hunks)
  • src/components/organisms/MainMenu.tsx (5 hunks)
  • src/i18n.ts (1 hunks)
  • src/index.tsx (1 hunks)
  • src/pages/Login.tsx (1 hunks)
  • src/pages/Register.tsx (5 hunks)
✅ Files skipped from review due to trivial changes (6)
  • public/locales/zh.json
  • public/locales/es.json
  • src/index.tsx
  • src/App.tsx
  • public/locales/ja.json
  • public/locales/de.json
🔇 Additional comments (3)
package.json (1)

39-41: LGTM! i18n dependencies are properly configured.

The added i18next packages and their versions are compatible and follow best practices for version ranges.

Also applies to: 62-62

src/components/molecules/NavBar.tsx (1)

64-66: LGTM! Good practice persisting language preference.

The implementation correctly persists the language preference to localStorage, ensuring a consistent experience across page reloads.

src/components/molecules/RecordingsTable.tsx (1)

Line range hint 411-443: LGTM! Good separation of translation keys in the options menu.

The translation keys for the options menu are well-organized and follow a consistent pattern.

Comment on lines +17 to +19
backend: {
loadPath: '/locales/{{lng}}.json',
},
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for missing translations

The backend configuration should include error handling for failed translation loading.

 backend: {
   loadPath: '/locales/{{lng}}.json',
+  loadPath: '/locales/{{lng}}.json',
+  addPath: '/locales/add/{{lng}}/{{ns}}',
+  allowMultiLoading: false,
+  reloadInterval: false,
+  crossDomain: false,
+  withCredentials: false,
+  overrideMimeType: false,
+  queryStringParams: { v: '1.0.0' },
 },

Committable suggestion skipped: line range outside the PR's diff.

"register_prompt": "Already have an account?",
"login_link": "Login",
"welcome_notification": "Welcome to Maxun!",
"error_notification": "Registeration Failed. Please try again."
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix typo in error message

There's a spelling error in the registration error message.

-      "error_notification": "Registeration Failed. Please try again."
+      "error_notification": "Registration Failed. Please try again."
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"error_notification": "Registeration Failed. Please try again."
"error_notification": "Registration Failed. Please try again."

Comment on lines +2 to +23
"login": {
"title": "Welcome Back!",
"email": "Email",
"password": "Password",
"button": "Login",
"loading": "Loading",
"register_prompt": "Don't have an account?",
"register_link": "Register",
"welcome_notification": "Welcome to Maxun!",
"error_notification": "Login Failed. Please try again."
},
"register": {
"title": "Register Account",
"email": "Email",
"password": "Password",
"button": "Register",
"loading": "Loading",
"register_prompt": "Already have an account?",
"login_link": "Login",
"welcome_notification": "Welcome to Maxun!",
"error_notification": "Registeration Failed. Please try again."
},
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add missing authentication error scenarios

The authentication sections are missing common error scenarios that should be localized.

Add these additional translation keys to the login and register sections:

 "login": {
   // ... existing keys ...
+  "invalid_email": "Please enter a valid email address",
+  "password_required": "Password is required",
+  "account_locked": "Account has been temporarily locked",
+  "network_error": "Network error. Please check your connection"
 },
 "register": {
   // ... existing keys ...
+  "email_taken": "This email is already registered",
+  "password_requirements": "Password must be at least 8 characters",
+  "terms_acceptance": "Please accept the terms and conditions"
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"login": {
"title": "Welcome Back!",
"email": "Email",
"password": "Password",
"button": "Login",
"loading": "Loading",
"register_prompt": "Don't have an account?",
"register_link": "Register",
"welcome_notification": "Welcome to Maxun!",
"error_notification": "Login Failed. Please try again."
},
"register": {
"title": "Register Account",
"email": "Email",
"password": "Password",
"button": "Register",
"loading": "Loading",
"register_prompt": "Already have an account?",
"login_link": "Login",
"welcome_notification": "Welcome to Maxun!",
"error_notification": "Registeration Failed. Please try again."
},
"login": {
"title": "Welcome Back!",
"email": "Email",
"password": "Password",
"button": "Login",
"loading": "Loading",
"register_prompt": "Don't have an account?",
"register_link": "Register",
"welcome_notification": "Welcome to Maxun!",
"error_notification": "Login Failed. Please try again.",
"invalid_email": "Please enter a valid email address",
"password_required": "Password is required",
"account_locked": "Account has been temporarily locked",
"network_error": "Network error. Please check your connection"
},
"register": {
"title": "Register Account",
"email": "Email",
"password": "Password",
"button": "Register",
"loading": "Loading",
"register_prompt": "Already have an account?",
"login_link": "Login",
"welcome_notification": "Welcome to Maxun!",
"error_notification": "Registeration Failed. Please try again.",
"email_taken": "This email is already registered",
"password_requirements": "Password must be at least 8 characters",
"terms_acceptance": "Please accept the terms and conditions"
},

Comment on lines +8 to +9
import { useTranslation } from 'react-i18next';
import i18n from '../../i18n';
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove unused i18n import

The i18n instance is imported but never used directly since you're using the useTranslation hook.

 import { useTranslation } from 'react-i18next';
-import i18n from '../../i18n';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { useTranslation } from 'react-i18next';
import i18n from '../../i18n';
import { useTranslation } from 'react-i18next';

Comment on lines 94 to 99
<Button href={`${apiUrl}/api-docs/`} target="_blank" rel="noopener noreferrer" sx={buttonStyles} startIcon={<Code />}>
Website To API
{t('mainmenu.apidocs')}
</Button>
<Button href="https://forms.gle/hXjgqDvkEhPcaBW76" target="_blank" rel="noopener noreferrer" sx={buttonStyles} startIcon={<CloudQueue />}>
Join Maxun Cloud
{t('mainmenu.feedback')}
</Button>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add aria-label for accessibility

The external links should have descriptive aria-labels for better accessibility.

-          <Button href={`${apiUrl}/api-docs/`} target="_blank" rel="noopener noreferrer" sx={buttonStyles} startIcon={<Code />}>
+          <Button 
+            href={`${apiUrl}/api-docs/`} 
+            target="_blank" 
+            rel="noopener noreferrer" 
+            sx={buttonStyles} 
+            startIcon={<Code />}
+            aria-label={t('mainmenu.apidocs_aria_label', 'Open API documentation in new tab')}>
             {t('mainmenu.apidocs')}
           </Button>
-          <Button href="https://forms.gle/hXjgqDvkEhPcaBW76" target="_blank" rel="noopener noreferrer" sx={buttonStyles} startIcon={<CloudQueue />}>
+          <Button 
+            href="https://forms.gle/hXjgqDvkEhPcaBW76" 
+            target="_blank" 
+            rel="noopener noreferrer" 
+            sx={buttonStyles} 
+            startIcon={<CloudQueue />}
+            aria-label={t('mainmenu.feedback_aria_label', 'Open feedback form in new tab')}>
             {t('mainmenu.feedback')}
           </Button>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Button href={`${apiUrl}/api-docs/`} target="_blank" rel="noopener noreferrer" sx={buttonStyles} startIcon={<Code />}>
Website To API
{t('mainmenu.apidocs')}
</Button>
<Button href="https://forms.gle/hXjgqDvkEhPcaBW76" target="_blank" rel="noopener noreferrer" sx={buttonStyles} startIcon={<CloudQueue />}>
Join Maxun Cloud
{t('mainmenu.feedback')}
</Button>
<Button
href={`${apiUrl}/api-docs/`}
target="_blank"
rel="noopener noreferrer"
sx={buttonStyles}
startIcon={<Code />}
aria-label={t('mainmenu.apidocs_aria_label', 'Open API documentation in new tab')}>
{t('mainmenu.apidocs')}
</Button>
<Button
href="https://forms.gle/hXjgqDvkEhPcaBW76"
target="_blank"
rel="noopener noreferrer"
sx={buttonStyles}
startIcon={<CloudQueue />}
aria-label={t('mainmenu.feedback_aria_label', 'Open feedback form in new tab')}>
{t('mainmenu.feedback')}
</Button>

Comment on lines +8 to +10
import { useTranslation } from 'react-i18next';
import i18n from '../i18n';

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove unnecessary i18n import.

The i18n import is not being used in this component. The useTranslation hook is sufficient for accessing translations.

 import { useTranslation } from 'react-i18next';
-import i18n from '../i18n';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { useTranslation } from 'react-i18next';
import i18n from '../i18n';
import { useTranslation } from 'react-i18next';

Comment on lines +8 to +9
import { useTranslation } from 'react-i18next';
import i18n from '../i18n';
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Translation files need standardization across languages

Translation files are present for all supported languages (en, de, es, ja, zh) but show inconsistencies:

  • Spanish (es) and Chinese (zh) translations are incomplete, missing many keys present in other languages
  • English (en), German (de), and Japanese (ja) have complete key structures
  • Spanish and Chinese have additional app.* keys not present in other languages
🔗 Analysis chain

Verify translation files are properly configured.

Let's ensure all required translation files are present and properly structured.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for translation files in public/locales
fd -t f -e json . public/locales

# Verify translation key structure consistency across files
for file in $(fd -t f -e json . public/locales); do
  echo "=== $file ==="
  jq -r 'paths | join(".")' "$file" | sort
done

Length of output: 3802


🛠️ Refactor suggestion

Remove unnecessary i18n import.

The i18n import is not being used in this component after removing the console.log statements.

 import { useTranslation } from 'react-i18next';
-import i18n from '../i18n';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { useTranslation } from 'react-i18next';
import i18n from '../i18n';
import { useTranslation } from 'react-i18next';

Comment on lines +13 to +14
console.log(i18n)
console.log(t)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove debug console.log statements.

Debug statements should not be committed to production code.

-   console.log(i18n) 
-   console.log(t)

Comment on lines 183 to 257
<IconButton
onClick={handleLangMenuOpen}
sx={{
display: "flex",
alignItems: "center",
borderRadius: "5px",
padding: "8px",
marginRight: "10px",
}}
>
<Typography variant="body1">{t("language")}</Typography>
</IconButton>
<Menu
anchorEl={langAnchorEl}
open={Boolean(langAnchorEl)}
onClose={handleMenuClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "right",
}}
transformOrigin={{
vertical: "top",
horizontal: "right",
}}
>
<MenuItem
onClick={() => {
changeLanguage("en");
handleMenuClose();
}}
>
English
</MenuItem>
<MenuItem
onClick={() => {
changeLanguage("es");
handleMenuClose();
}}
>
Español
</MenuItem>
<MenuItem
onClick={() => {
changeLanguage("ja");
handleMenuClose();
}}
>
日本語
</MenuItem>
<MenuItem
onClick={() => {
changeLanguage("ar");
handleMenuClose();
}}
>
العربية
</MenuItem>
<MenuItem
onClick={() => {
changeLanguage("zh");
handleMenuClose();
}}
>
中文
</MenuItem>
<MenuItem
onClick={() => {
changeLanguage("de");
handleMenuClose();
}}
>
German

</MenuItem>
</Menu>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Refactor duplicate language menu code.

The language menu implementation is duplicated for logged-in and logged-out states. This violates the DRY principle and makes maintenance harder.

Extract the language menu into a separate component:

+const LanguageMenu = ({ anchorEl, handleClose }) => {
+  const { t, i18n } = useTranslation();
+  
+  const changeLanguage = (lang: string) => {
+    i18n.changeLanguage(lang);
+    localStorage.setItem("language", lang);
+    handleClose();
+  };
+
+  return (
+    <Menu
+      anchorEl={anchorEl}
+      open={Boolean(anchorEl)}
+      onClose={handleClose}
+      anchorOrigin={{
+        vertical: "bottom",
+        horizontal: "right",
+      }}
+      transformOrigin={{
+        vertical: "top",
+        horizontal: "right",
+      }}
+    >
+      <MenuItem onClick={() => changeLanguage("en")}>English</MenuItem>
+      <MenuItem onClick={() => changeLanguage("es")}>Español</MenuItem>
+      <MenuItem onClick={() => changeLanguage("ja")}>日本語</MenuItem>
+      <MenuItem onClick={() => changeLanguage("ar")}>العربية</MenuItem>
+      <MenuItem onClick={() => changeLanguage("zh")}>中文</MenuItem>
+      <MenuItem onClick={() => changeLanguage("de")}>German</MenuItem>
+    </Menu>
+  );
+};

Then use it in both places:

-<Menu anchorEl={langAnchorEl} ...>
-  <MenuItem onClick={() => { changeLanguage("en"); handleMenuClose(); }}>
-    English
-  </MenuItem>
-  ...
-</Menu>
+<LanguageMenu anchorEl={langAnchorEl} handleClose={handleMenuClose} />

Also applies to: 260-325

@amhsirak amhsirak changed the title Internationalization Support (i18n) feat: Internationalization Support (i18n) Dec 10, 2024
@amhsirak amhsirak added the Type: Feature New features label Dec 10, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (6)
src/components/molecules/RunsTable.tsx (5)

21-29: Consider enhancing type safety for column definitions.

While the column definitions are correctly moved outside the component, we can improve type safety.

Consider this enhancement:

-export const columns: readonly Column[] = [
+export const columns = [
   { id: 'runStatus', label: 'Status', minWidth: 80 },
   { id: 'name', label: 'Name', minWidth: 80 },
   { id: 'startedAt', label: 'Started At', minWidth: 80 },
   { id: 'finishedAt', label: 'Finished At', minWidth: 80 },
   { id: 'settings', label: 'Settings', minWidth: 80 },
   { id: 'delete', label: 'Delete', minWidth: 80 },
-];
+] as const satisfies readonly Column[];

This ensures complete type inference and immutability.


70-76: Consider memoizing translated columns.

While the translation implementation is correct, the column translation mapping runs on every render.

Consider using useMemo:

-  const translatedColumns = columns.map(column => ({
+  const translatedColumns = React.useMemo(() => columns.map(column => ({
     ...column,
     label: t(`runstable.${column.id}`, column.label)
-  }));
+  })), [t]);

102-108: Enhance error handling in data fetching.

While error notification is added, the error handling could be more specific.

Consider enhancing error handling:

   if (runs) {
     const parsedRows: Data[] = runs.map((run: any, index: number) => ({
       id: index,
       ...run,
     }));
     setRows(parsedRows);
   } else {
-    notify('error', 'No runs found. Please try again.');
+    notify('error', t('runstable.errors.noRuns', 'No runs found. Please try again.'));
   }

116-117: Consider optimizing effect dependencies.

The current dependencies might cause unnecessary rerenders.

Consider using a ref for tracking rows length:

+  const rowsLengthRef = React.useRef(rows.length);
+  React.useEffect(() => {
+    rowsLengthRef.current = rows.length;
+  }, [rows.length]);

   useEffect(() => {
-    if (rows.length === 0 || rerenderRuns) {
+    if (rowsLengthRef.current === 0 || rerenderRuns) {
       fetchRuns();
       setRerenderRuns(false);
     }
-  }, [rerenderRuns, rows.length, setRerenderRuns]);
+  }, [rerenderRuns, setRerenderRuns]);

143-143: Consider centralizing translation keys.

While the translations are implemented correctly, consider managing translation keys centrally.

Create a constants file for translation keys:

// src/constants/translationKeys.ts
export const TRANSLATION_KEYS = {
  RUNS_TABLE: {
    TITLE: 'runstable.runs',
    SEARCH: 'runstable.search',
    // ... other keys
  }
} as const;

Then use these constants:

-          {t('runstable.runs', 'Runs')}
+          {t(TRANSLATION_KEYS.RUNS_TABLE.TITLE, 'Runs')}

Also applies to: 147-147

src/components/molecules/NavBar.tsx (1)

72-91: Consider replacing inline styles with styled-components

There are multiple instances of inline styles applied to div and IconButton components (lines 72-91 and 93-126). Using inline styles can make the code harder to read and maintain.

Consider moving these styles into styled-components or a separate styling object to improve readability and maintain consistency.

Also applies to: 93-126

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 0772342 and 5663abe.

📒 Files selected for processing (5)
  • public/locales/en.json (1 hunks)
  • public/locales/ja.json (1 hunks)
  • src/components/molecules/NavBar.tsx (1 hunks)
  • src/components/molecules/RunsTable.tsx (9 hunks)
  • src/pages/Register.tsx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/pages/Register.tsx
  • public/locales/ja.json
🔇 Additional comments (7)
src/components/molecules/RunsTable.tsx (3)

2-3: LGTM! Import changes look good.

The necessary imports for i18n support and UI components have been added correctly.

Also applies to: 12-14


Line range hint 39-69: LGTM! Type definitions are well-structured.

The explicit FC typing and interface definitions improve type safety and maintainability.


Line range hint 167-175: LGTM! Column rendering is well implemented.

The translation integration with column rendering is clean and type-safe.

src/components/molecules/NavBar.tsx (2)

210-259: Refactor duplicated language menu into a separate component

The language menu implementation is duplicated for both logged-in users (lines 210-259) and logged-out users (lines 287-327), violating the DRY (Don't Repeat Yourself) principle. This duplication can make maintenance harder and increase the risk of inconsistencies.

Consider extracting the language menu into a separate component and reuse it in both places to improve maintainability.

Also applies to: 287-327


118-125: Verify the security implications of embedding external content via iframe

The iframe in lines 118-125 embeds content from https://ghbtns.com/github-btn.html, which is an external source. Embedding external content can introduce security risks such as cross-site scripting (XSS) attacks or other vulnerabilities.

Ensure that embedding this external iframe is necessary and does not expose the application to potential security risks.

Run the following script to check for any known security issues with the external URL:

public/locales/en.json (2)

22-22: Fix typo in error message

There's a spelling error in the registration error message on line 22.

-      "error_notification": "Registeration Failed. Please try again."
+      "error_notification": "Registration Failed. Please try again."

2-23: Add missing authentication error messages

The authentication sections are missing common error messages that should be localized. This can enhance user experience by providing clear feedback.

Consider adding these additional translation keys to the login and register sections:

 "login": {
   // ... existing keys ...
+  "invalid_email": "Please enter a valid email address.",
+  "password_required": "Password is required.",
+  "account_locked": "Your account has been temporarily locked.",
+  "network_error": "Network error. Please check your connection."
 },
 "register": {
   // ... existing keys ...
+  "email_taken": "This email is already registered.",
+  "password_requirements": "Password must be at least 8 characters.",
+  "terms_acceptance": "Please accept the terms and conditions."
 }

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (5)
src/pages/Register.tsx (1)

Missing translation keys in Chinese (zh) and Spanish (es) locale files

The verification reveals that the register-related translation keys are missing in some locale files:

  • Chinese (zh.json) and Spanish (es.json) files only contain login-related translations
  • English (en.json), German (de.json), and Japanese (ja.json) have the complete register translations

Required actions:

  • Add missing register section with all required keys to public/locales/zh.json
  • Add missing register section with all required keys to public/locales/es.json
🔗 Analysis chain

Line range hint 88-132: Verify translation key coverage.

All UI text has been properly internationalized. Let's verify that all required translation keys exist in the locale files.


Let me generate another verification script to check the actual content of the locale files, as the previous output doesn't show the translation values.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if all required translation keys exist in locale files
# Expected: All keys should be present in all locale files

# Define the required keys
REQUIRED_KEYS=(
  "register.title"
  "register.email"
  "register.password"
  "register.button"
  "register.register_prompt"
  "register.login_link"
  "register.welcome_notification"
  "register.error_notification"
)

# Find all locale files
fd -e json . public/locales -x echo "Checking {}"

# Check each key in locale files
for key in "${REQUIRED_KEYS[@]}"; do
  echo "Checking key: $key"
  fd -e json . public/locales -x jq ".. | objects | select(has(\"$key\")) | .[\"$key\"]" {}
done

Length of output: 2296


Script:

#!/bin/bash
# Let's examine the actual content of locale files to verify the translation keys
echo "Checking locale files content:"
fd -e json . public/locales -x cat {}

# Alternative approach using jq to get a better formatted view of register.* keys
echo -e "\nChecking register.* keys in each locale file:"
fd -e json . public/locales -x sh -c 'echo "=== {} ==="; jq ".. | objects | with_entries(select(.key | startswith(\"register.\")))" {}'

Length of output: 5867

src/components/molecules/RecordingsTable.tsx (4)

67-90: Simplify column definitions.

The current column definitions are verbose and repetitive. Consider simplifying them for better maintainability.

-  const columns: readonly Column[] = [
-    { id: 'interpret', label: t('recordingtable.run'), minWidth: 80 },
-    { id: 'name', label: t('recordingtable.name'), minWidth: 80 },
-    {
-      id: 'schedule',
-      label: t('recordingtable.schedule'),
-      minWidth: 80,
-    },
-    // ... more columns
-  ];
+  const COLUMN_IDS = ['interpret', 'name', 'schedule', 'integrate', 'settings', 'options'] as const;
+  
+  const columns: readonly Column[] = COLUMN_IDS.map(id => ({
+    id,
+    label: t(`recordingtable.${id === 'interpret' ? 'run' : id}`),
+    minWidth: 80
+  }));

428-442: Consider memoizing menu items.

The menu items are recreated on every render. Consider memoizing them for better performance.

+ const menuItems = React.useMemo(() => [
+   {
+     icon: <Edit fontSize="small" />,
+     text: t('recordingtable.edit'),
+     onClick: handleEdit
+   },
+   {
+     icon: <DeleteForever fontSize="small" />,
+     text: t('recordingtable.delete'),
+     onClick: handleDelete
+   },
+   {
+     icon: <ContentCopy fontSize="small" />,
+     text: t('recordingtable.duplicate'),
+     onClick: handleDuplicate
+   }
+ ], [t, handleEdit, handleDelete, handleDuplicate]);

  return (
    <Menu {...menuProps}>
-     <MenuItem onClick={() => { handleEdit(); handleClose(); }}>
-       <ListItemIcon><Edit fontSize="small" /></ListItemIcon>
-       <ListItemText>{t('recordingtable.edit')}</ListItemText>
-     </MenuItem>
-     {/* ... other items */}
+     {menuItems.map(({ icon, text, onClick }) => (
+       <MenuItem key={text} onClick={() => { onClick(); handleClose(); }}>
+         <ListItemIcon>{icon}</ListItemIcon>
+         <ListItemText>{text}</ListItemText>
+       </MenuItem>
+     ))}
    </Menu>
  );

Line range hint 1-461: Consider implementing a translation key management system.

While the internationalization implementation is thorough, managing translation keys across a large application can become challenging. Consider implementing:

  1. A type-safe translation key system
  2. A central registry of translation keys
  3. Runtime validation of translation key existence

This will help catch missing translations early and improve maintainability.


Missing translation keys in all locale files

The translation keys recordingtable.modal.title, recordingtable.modal.label, and recordingtable.modal.button are not present in any of the locale files (de.json, en.json, es.json, ja.json, zh.json). These keys need to be added to all translation files to ensure proper internationalization of the modal.

  • Add missing keys to public/locales/en.json
  • Add missing keys to public/locales/de.json
  • Add missing keys to public/locales/es.json
  • Add missing keys to public/locales/ja.json
  • Add missing keys to public/locales/zh.json
🔗 Analysis chain

Line range hint 308-323: Verify modal translation keys.

The modal UI elements have been properly internationalized. Let's verify the translation keys exist.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if modal translation keys exist
# Expected: All keys should be present in all locale files

fd -e json . public/locales -x jq '
  select(
    has("recordingtable.modal.title") and
    has("recordingtable.modal.label") and
    has("recordingtable.modal.button")
  )
' {}

Length of output: 181


Script:

#!/bin/bash
# First, let's check if the locales directory exists and list its contents
fd -t d "locales$"

# Then let's find all json files in the project that might contain translations
fd -e json

# Finally, let's try to find any files containing these translation keys
rg -l "recordingtable\.modal\.(title|label|button)"

Length of output: 384


Script:

#!/bin/bash
# Let's check the content of each locale file for these specific translation keys
for locale in public/locales/*.json; do
  echo "=== $locale ==="
  jq '.["recordingtable.modal.title"], .["recordingtable.modal.label"], .["recordingtable.modal.button"]' "$locale"
done

Length of output: 1264

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 5663abe and 2872e1b.

📒 Files selected for processing (4)
  • package.json (3 hunks)
  • src/components/molecules/NavBar.tsx (1 hunks)
  • src/components/molecules/RecordingsTable.tsx (10 hunks)
  • src/pages/Register.tsx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • package.json
  • src/components/molecules/NavBar.tsx
🔇 Additional comments (1)
src/pages/Register.tsx (1)

8-10: Remove unnecessary i18n import.

The i18n import is not being used in this component. The useTranslation hook is sufficient for accessing translations.

Comment on lines +52 to +53

notify("error", error.response.data || t('register.error_notification'));
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error message handling.

The current implementation directly uses error.response.data which might expose sensitive information or show technical details to users. Consider using translated error messages for known error cases.

-      notify("error", error.response.data || t('register.error_notification'));
+      const errorMessage = t([
+        `register.errors.${error.response?.data?.code}`,
+        'register.error_notification'
+      ]);
+      notify("error", errorMessage);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
notify("error", error.response.data || t('register.error_notification'));
const errorMessage = t([
`register.errors.${error.response?.data?.code}`,
'register.error_notification'
]);
notify("error", errorMessage);

@amhsirak amhsirak changed the base branch from master to develop December 10, 2024 16:35
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (1)
src/components/molecules/NavBar.tsx (1)

300-306: Add RTL layout support for Arabic language

While Arabic language is supported, there's no visible implementation of RTL (Right-to-Left) layout support. Consider:

  1. Using Material-UI's RTL support via direction prop
  2. Adding RTL-aware styling for components
  3. Testing the layout in RTL mode

Example implementation:

const isRTL = i18n.dir() === 'rtl';

// In your theme or component
const theme = createTheme({
  direction: isRTL ? 'rtl' : 'ltr',
});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 2872e1b and 100fdb9.

📒 Files selected for processing (2)
  • package.json (2 hunks)
  • src/components/molecules/NavBar.tsx (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • package.json
🔇 Additional comments (3)
src/components/molecules/NavBar.tsx (3)

13-13: LGTM: Required i18n imports added correctly

The necessary imports for react-i18next and the Language icon have been properly added.

Also applies to: 21-21


48-48: LGTM: Language state management implemented properly

The language selection state and handlers are well-implemented with proper persistence to localStorage.

Also applies to: 88-90, 114-117


262-324: Refactor duplicate language menu code

The language menu implementation remains duplicated between logged-in and logged-out states.

Also applies to: 339-392

style={{ borderRadius: "5px", margin: "5px 0px 5px 15px" }}
/>
<div style={{ padding: "11px" }}>
<ProjectName>Maxun</ProjectName>
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add missing translations for hardcoded strings

Several strings remain hardcoded instead of using translation keys:

  • "Maxun" title
  • Language names in the menu ("English", "Español", etc.)

Consider using translation keys for better i18n support:

-<ProjectName>Maxun</ProjectName>
+<ProjectName>{t("app.name")}</ProjectName>

-English
+{t("languages.english")}

Also applies to: 281-281, 289-289, 297-297, 305-305, 313-313, 321-321

@amhsirak amhsirak added Status: In Review This PR is being reviewed Status: Work In Progess This issue/PR is actively being worked on labels Dec 10, 2024
@amhsirak amhsirak marked this pull request as draft December 17, 2024 01:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: In Review This PR is being reviewed Status: Work In Progess This issue/PR is actively being worked on Type: Feature New features
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants