CSC/ECE 517 Spring 2025 - E2517. Reimplement internationalization (frontend + backend)
Important Links
- Git PR (front-end) - https://github.com/expertiza/reimplementation-front-end/pull/89
- Git PR (back-end) - https://github.com/expertiza/reimplementation-back-end/pull/174
- GitHub Repository (front-end) - https://github.com/ishani-rajput/reimplementation-front-end
- GitHub Repository (back-end) - https://github.com/ishani-rajput/reimplementation-back-end
- Demo Video - https://drive.google.com/file/d/1sHlc-asPUTG9fTKjaEiGPWIX5mgqRJ34/view?usp=sharing
- Website - http://152.7.178.94:3001/login
Expertiza
Expertiza is an open-source web application developed primarily for peer assessment and collaborative learning. It allows instructors to create assignments where students can submit their work, review the work of their peers, and receive feedback from both peers and instructors. Expertiza supports various assignment formats, including team-based projects, individual submissions, and metareviews (reviews of reviews). Its flexible design offers features like topic sign-ups, staggered deadlines, plagiarism checks, and detailed rubrics, making it a powerful tool for promoting active learning, accountability, and continuous improvement in academic settings.
Overview
The objective of this project is to reimplement the Internationalization feature for both frontend and backend of Expertiza. This includes: Adding multi-language support, particularly Hindi (Indian) translations. Ensuring all user-facing messages, buttons, flash notices, and model validations can be switched based on the selected locale. Improving the test coverage with RSpec for all major controllers.
Problem
Currently, all Expertiza screens can only be viewed in English. Many Expertiza users are from other countries. This is a problem since this limits the accessibility of Expertiza.

Survey of home country of Expertiza users for a given course
Solution Approach
The frontend interface will support switching between English and Hindi (Indian) languages, ensuring all user-facing buttons, flash messages, and error notices reflect the selected language. Additionally, admin users will have access to a language selector to change the locale dynamically. On the backend, model validation messages and system notices will be moved to locale files to ensure consistency across different languages. Comprehensive RSpec tests have been added for major controllers including User, Course, Institution, Assignment, Participant, and Role to verify correct functionality.
Scope
The scope of this project is limited however only to static strings. i.e. user-generated content will not be automatically translated to other languages.
Breaking down internationalization into 3 phases:

1. Language Preference Selection:
Steps:
1.Check if the user has selected a preferred language in their profile.
2.If neither is set, use the application's default language (English).

2: Dynamic Rendering of Views:
Steps:
1.Fetch translations for all static strings (stored in the backend config/locales folder for Rails and respective i18n JSON files in frontend).
2.Replace the UI elements dynamically based on the selected language.
3.Use translation helpers in Rails views and i18n functions in React frontend.
3.Handling Missing Translations:
1.If any text string lacks a translation in the selected language:
2. Ensure UI consistency and no crashes due to missing translations.
Design
1. Language Preference Selection:
The primary goal is to determine the correct language in which to render each page based on user preferences. The logic we adopt is as follows:
The following logic is added to ApplicationController to enforce this:
before_action :set_locale def set_locale I18n.locale = current_user&.locale || I18n.default_locale end
This ensures dynamic, per-user language selection.
Frontend Integration:
On the frontend, the language preference is selected by the user on the Profile Edit page. Upon submission, the following logic is executed to update the preference:
const handleSubmit = (values, { setSubmitting }) => { const selectedLang = values.language === 'Hindi' ? 'hi' : 'en'; // Update React-i18next and local storage i18n.changeLanguage(selectedLang); localStorage.setItem('language', selectedLang); // Send language preference to backend const payload = { ...values, locale: selectedLang }; const userId = localStorage.getItem('userId'); fetch(`/api/v1/users/${userId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify(payload), }) .then((res) => res.json()) .then(() => setSubmitting(false)) .catch(() => setSubmitting(false)); };
This mechanism ensures that:
2.Rendering Dynamic Content in Selected Language:
Once the locale is determined, the actual views need to render text in the selected language.
Rails' built-in I18n gem allows storing translations in .yml files for each supported language (e.g., en.yml, hi.yml):
Example:
en: assignments": { "create_title": "Create Assignment", "update_title": "Update Assignment: {{assignmentName}}", "success_message": "Assignment {{assignmentName}} {{mode}}d successfully!", "close": "Close", "create": "Create", hi: assignments": { "create_title": "असाइनमेंट बनाएं", "update_title": "असाइनमेंट अपडेट करें: {{assignmentName}}", "success_message": "असाइनमेंट {{assignmentName}} सफलतापूर्वक {{mode}} किया गया!", "close": "बंद करें", "create": "बनाएं",
instead of:
<h2>Create Assignment</h2>
write:
<h2><%= t('assignments.create_title') %></h2>
Frontend (React), It’s the React version of i18next, allowing us to dynamically load and render language-specific text.
Example:
English (src/locales/en/translation.json):
{ "assignments": { "create_title": "Create Assignment", "create": "Create" } }
Hindi (src/locales/hi/translation.json):
{ "assignments": { "create_title": "असाइनमेंट बनाएं", "create": "बनाएं" } }
Usage in React component:
Before (hardcoded English):
<h2>Create Assignment</h2> <button>Create</button>
After (dynamic, supports multi-language):
import { useTranslation } from 'react-i18next'; const AssignmentComponent = () => { const { t } = useTranslation(); return ( <div> <h2>{t('assignments.create_title')}</h2> <button>{t('assignments.create')}</button> </div> ); };
Language switching:
React will automatically reload the translations and the page content will change to Hindi, without reloading the entire app!
i18n.changeLanguage('hi'); // Hindi localStorage.setItem('language', 'hi');
3.Handling Missing Translations Gracefully:
What if some keys are not translated in the target language (e.g., Hindi)?
We enable fallback mechanisms:
config.i18n.default_locale = :en config.i18n.available_locales = [:en, :hi] config.i18n.fallbacks = true config.i18n.enforce_available_locales = true
import i18n from "i18next"; import { initReactI18next } from "react-i18next"; import enTranslation from "./locales/en/translation.json"; import hiTranslation from "./locales/hi/translation.json"; i18n.use(initReactI18next).init({ resources: { en: { translation: enTranslation }, hi: { translation: hiTranslation }, }, lng: localStorage.getItem("language") || "en", fallbackLng: "en", interpolation: { escapeValue: false }, }); export default i18n;
Thus, if a key is missing, the system falls back to English, ensuring no broken UI.
Alternate approaches
1. Why not simply swap out entire views for each language instead of translating each text individually?
At first glance, creating separate static views for each supported language (e.g., one view file for English, one for Hindi, etc.) might seem simpler. However, this method has major drawbacks:
Instead, we opted for dynamic translation at the element level using the I18n.t helper function, keeping the view logic in one place and swapping out only the text as per the selected language.
2. Why did we choose the I18n gem instead of building our own translation mechanism? While implementing a custom translation mechanism from scratch seemed flexible, we decided to leverage Rails' built-in I18n gem due to the following reasons:
We evaluated two options for storing user language preferences:

Use Case Diagram
Actors:
Description:
This use case addresses how language preferences are handled in Expertiza. All users (students, instructors, and admins) have the ability to set their preferred language on their profile page. The system dynamically renders all pages based on these preferences, with fallback mechanisms in case of missing translations.
Main Flow:
1.User sets preferred language:
3.Rendering pages based on language:
Preconditions:
Postconditions:
Major design patterns and principles used
1.DRY Principle - Usage of i18n t Function
The (DRY) principle is heavily used in this project by leveraging the t function provided by the i18n library. Instead of hardcoding language strings throughout the views, the t function abstracts the logic of fetching the correct translation based on the current locale. Additionally, it handles fallback mechanisms automatically. This ensures that the localization logic is not repeated at every view element but is centralized and reusable, promoting clean, maintainable code.
2.Chain of Responsibility

The fallback mechanism in i18n adheres to the Chain of Responsibility design pattern. When a translation for a key in the user's selected language is not found, the library proceeds to check fallback languages (e.g., defaulting to English). This chain continues until a valid translation is found. This pattern decouples the translation request from the specific language files, making the system extensible and resilient to missing translations.
3.Open/Closed Principle & Strategy Pattern - Dynamic Language Selection:'
The decision-making process for selecting the appropriate language adheres to the Open/Closed Principle, meaning the system is open to future extensions (like course-specific language settings) without requiring changes to the existing core logic.
Currently, the system selects the locale based on the user's profile preference:
To support this with flexibility, a Strategy Pattern is conceptually applied — the language selection logic is delegated to a single method (set_locale) in the controller. This method can be easily extended (e.g., to include course-specific behavior later) without modifying the parts that rely on it.
Database Design
To enable Internationalization (i18n) and allow users to set their preferred language, modifications have been made to the database schema, particularly in the users table.
Migration Snippet:
t.string :locale
Application default locale (en).
Benefits:
1.Persistence Across Sessions:
User’s language preference is saved in the database, so it remains consistent across multiple logins.
2.Flexibility:
Supports multiple languages dynamically without major schema changes. You can add new locales anytime.
3.Hierarchy of Preference:
Test Plan
Objective:
To verify that internationalization features (specifically Hindi translations) are correctly implemented across the Expertiza platform. The testing focuses on ensuring that static strings on various pages (Profile, Assignments, Courses) are translated correctly based on the user’s language preference. It also verifies fallback behavior when translations are missing.
Manual Testing:
Through manual testing, we aim to identify if all the features of the application are working as intended when the language conversion occurs.
Screenshots of translated pages (Profile, Assignments, Courses) will be attached to verify correct translation rendering.
Login Credentials
username: admin2@example.com
password: password123
Scenarios:
Scenario 1: User Preference Hindi - Profile Page
1.Log in to Expertiza as a student.
2.Navigate to the “User Profile Information” page.
3.Navigate to the “User Profile Information” page.
4.Verify:


Scenario 2: User Preference Hindi - Assignment & Course Page
1.Log in as a student.
2.Change preferred language to Hindi.
3.Visit the Assignments page and verify Hindi translations.
4.Visit the Courses page and verify Hindi translations.
5.If translation keys are missing:



Scenario 3: Missing Translation Key Fallback
1.Log in as any user with Hindi preference.
2.Visit a page with incomplete Hindi translation keys.
3.Verify:
RSpec Test Cases
As part of this project, we ensured robust backend testing by writing comprehensive RSpec tests for core entities related to the internationalization (I18n) feature. These tests validate CRUD operations, locale handling, and edge cases across various controllers. Additionally, we implemented locale-specific tests to ensure proper internationalized error messages and responses.
Entities Covered:
1. Assignment Controller Tests:
Assignment Rspec Test Snippet:
# ------------------------------------------------------------------------- # DELETE /api/v1/assignments/{id} # ------------------------------------------------------------------------- path '/api/v1/assignments/{id}' do parameter name: 'id', in: :path, type: :integer, description: 'Assignment ID' delete('Delete an assignment') do tags 'Assignments' produces 'application/json' consumes 'application/json' parameter name: 'Content-Type', in: :header, type: :string let('Content-Type') { 'application/json' } response(200, 'successful') do let(:id) { assignment.id } run_test! do |response| data = JSON.parse(response.body) expect(response).to have_http_status(:ok) expect(data['message']).to eq(I18n.t('assignment.deleted_successfully', locale: :en)) end end response(404, 'Assignment not found') do let(:id) { 999 } run_test! do |response| data = JSON.parse(response.body) expect(response).to have_http_status(:not_found) expect(data['error']).to eq(I18n.t('assignment.not_found', locale: :en)) end end response(404, 'Assignment not found in Hindi') do let(:id) { 999 } let!(:hindi_user) do User.create!( name: "hindiuser", full_name: "Hindi User", email: "hindi@example.com", password_digest: "password", role_id: @roles[:instructor].id, locale: :hi ) end let(:token) { JsonWebToken.encode({ id: hindi_user.id }) } let(:Authorization) { "Bearer #{token}" } run_test! do |response| data = JSON.parse(response.body) expect(response).to have_http_status(:not_found) expect(data['error']).to eq(I18n.t('assignment.not_found', locale: :hi)) end end end end
2. Course Controller Tests:
Course Rspec Test Snippet:
esponse(200, 'TA removed message is internationalized') do let!(:hindi_user) do User.create!( name: "hindiuser", full_name: "Hindi User", email: "hindi@example.com", password_digest: "password", role_id: @roles[:instructor].id, locale: :hi ) end let(:token) { JsonWebToken.encode({ id: hindi_user.id }) } let(:Authorization) { "Bearer #{token}" } before do allow_any_instance_of(Course).to receive(:remove_ta).and_return({ success: true, ta_name: ta.name }) end run_test! do |response| data = JSON.parse(response.body) expected_message = I18n.t('course.ta_removed', ta_name: ta.name, locale: :hi) expect(response).to have_http_status(:ok) expect(data['message']).to eq(expected_message) end end
3.Roles Controller Tests:
4. Institution Controller Tests:
5. Participant Controller Tests:
Test Suite: All RSpec tests validating I18n functionality pass successfully, ensuring correct localized responses across controllers.
Future Scope
1. Expand to More Languages While the current implementation focuses on supporting Hindi as an additional language alongside English, the system has been designed with scalability in mind. The modularity of the i18n framework, combined with the structured approach to handling locale preferences in both the frontend and backend, allows seamless extension to other languages in the future. Adding new languages such as Spanish, Chinese, French, etc., would simply involve providing appropriate translations in the YAML files and ensuring their integration with the existing locale management system.
2. Introduce Course-Specific Language Overrides Currently, the application supports language selection based solely on individual user preferences. In the future, support for course-level default languages can be introduced — allowing instructors to specify a preferred language for their courses. This would be particularly useful for course-specific pages viewed by students who haven't set a personal language preference. Implementing this feature would involve auditing course-related views and ensuring the locale dynamically respects either the student’s preference or the course’s default, thereby providing a more personalized and consistent multilingual experience.
team
members
Ishani Rajput(irajput@ncsu.edu)
Elnaz Ghotbitaheri(eghotbi@ncsu.edu)
Ryan Gallagher(rtgalla2@ncsu.edu)
Mentor
Vihar Manojkumar Shah(vshah23@ncsu.edu)