Localization - #15
Localization#15
Conversation
…d enhance button interactions
…gin and signup views Replace hardcoded strings in LoginView and SignUpView with translation keys for internationalization support. Add TranslationService dependency to SignUpView and update both English and Finnish property files with new authentication-related translation keys.
…views Add TranslationService to GeneratorWizardView, HelpView, HistoryView, MainLayout, NotificationsView, ProfileView, ResumeManagerView, and SettingsView. Replace hardcoded UI strings with translation keys for all user-facing text including titles, subtitles, buttons, placeholders, and notifications. Update language resource files with comprehensive translations: - Expand messages.properties with 150+ new keys covering generator wizard steps, history filters, help sections, notifications, resume manager, and settings - Update messages_fi.properties with complete Finnish translations for all new keys - Update messages_zh.properties with complete Chinese translations for all new keys Refactor SettingsView language selection to use native language names (Suomi, Português, فارسی, 中文) instead of English names, with proper language code mapping for persistence.
…keys in dashboard and settings views
Update DashboardView to use translation keys for time-related strings ("Just now", "h ago", "Yesterday", etc.) and "Quick Actions" heading. Modify HistoryView to localize "Load more generations" button text. Refactor SettingsView language selection to use translation keys for language names and notification messages instead of hardcoded strings.
Add corresponding translation keys to resource files:
- Add dashboard time-related keys to messages.properties, messages_fi.properties, and messages_zh.properties
- Add settings language option keys and notification messages to all three resource files
- Add mainlayout navigation keys to messages.properties
Break long lines across multiple view classes and service to improve code readability. Adjust indentation and formatting in several files including HistoryView and ResumeManagerView for consistent style throughout the codebase.
…nto adding-persian
Persian QA completed
Replace region-specific locale files with language-only versions for Persian, Portuguese, and Urdu. Add Urdu language option to main properties file and provide complete translation sets for all three languages. Changes: - Add Urdu language setting to messages.properties - Replace messages_fa_ir.properties with messages_fa.properties (complete Persian translations) - Replace messages_pt_br.properties with messages_pt.properties (complete Portuguese translations) - Replace messages_ur_pk.properties with messages_ur.properties (complete Urdu translations)
Add header comments to all localization files for clarity. Reorganize sections in Portuguese and Urdu files to match standard structure. Fix indentation issues in Finnish file. Add missing language settings to Finnish and Chinese files. Complete Persian generator and error sections. Changes: - Add header comments to all translation files - Reorganize sections in Portuguese and Urdu files - Fix indentation in Finnish file - Add language settings to Finnish and Chinese files - Complete Persian generator and error translations
Add Urdu locale to the list of supported languages in TranslationService. Update LandingView and SettingsView to include Urdu in language selection dropdowns and handle display name mapping.
Fix typos and incorrect terms in Portuguese translation file, including replacing Chinese characters with proper Portuguese equivalents and correcting grammatical errors. Improve Urdu translation quality by removing English words in parentheses, replacing mixed-language terms with proper Urdu equivalents, and fixing incomplete translations.
…nguages Add comprehensive translation keys for history section functionality including cover letter management, filtering, date ranges, export operations, and confirmation dialogs. Introduce profile section translations for account details, security settings, password management, and user preferences. Update existing translations in Farsi, Finnish, Portuguese, Urdu, and Chinese for consistency and improved localization quality.
Replace hardcoded notification strings with translation service calls across HelpView, HistoryView, ProfileView, and ResumeManagerView. This ensures all user-facing messages are properly localized and maintain consistency with the translation framework established in previous i18n commits.
… keys Add comprehensive notification translation keys across Farsi, Finnish, Portuguese, Urdu, and Chinese locales. Remove duplicate profile and history section entries in localized property files to maintain clean translation resources.
Reformat multi-line Notification.show() calls across HelpView, HistoryView, ProfileView, and ResumeManagerView to improve code readability and maintain consistent line length.
There was a problem hiding this comment.
Pull request overview
This PR expands and refactors the app’s i18n support by adding new locales (Portuguese/Portuguese, Persian, Chinese, Urdu), removing some previous locales, and migrating many Vaadin UI views from hardcoded strings to TranslationService keys so the UI becomes fully translatable.
Changes:
- Updated
TranslationServicelocale list and language parsing to supportpt,fa,zh,ur. - Refactored multiple views (landing/auth/dashboard/history/generator/settings/profile/help/notifications/resume manager) to use translation keys for user-facing text.
- Added/updated message bundles (notably new
messages_zh.propertiesandmessages_pt.properties) and removed some legacy locale bundles.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main/resources/messages.properties | Expanded key set for newly localized UI text (default bundle) |
| src/main/resources/messages_zh.properties | Added Chinese translations bundle |
| src/main/resources/messages_pt.properties | Added Portuguese translations bundle |
| src/main/resources/messages_fi.properties | Extended Finnish bundle to match new keys |
| src/main/resources/messages_sv.properties | Removed Swedish bundle |
| src/main/resources/messages_fr.properties | Removed French bundle |
| src/main/resources/messages_de.properties | Removed German bundle |
| src/main/java/com/clbooster/app/i18n/TranslationService.java | Updated supported locales + parsing logic for new languages |
| src/main/java/com/clbooster/app/views/LandingView.java | Added language switcher + translated landing content |
| src/main/java/com/clbooster/app/views/LoginView.java | Replaced UI strings with translation keys |
| src/main/java/com/clbooster/app/views/SignUpView.java | Replaced UI strings with translation keys, including ToS/Privacy dialogs |
| src/main/java/com/clbooster/app/views/MainLayout.java | Localized nav/drawer labels |
| src/main/java/com/clbooster/app/views/DashboardView.java | Localized dashboard sections + relative time labels |
| src/main/java/com/clbooster/app/views/GeneratorWizardView.java | Localized wizard steps/forms/notifications and refactored tone selection |
| src/main/java/com/clbooster/app/views/HistoryView.java | Localized history UI and notifications |
| src/main/java/com/clbooster/app/views/SettingsView.java | Localized settings UI and updated language selector options |
| src/main/java/com/clbooster/app/views/ProfileView.java | Localized profile UI, tabs, and notifications |
| src/main/java/com/clbooster/app/views/ResumeManagerView.java | Localized resume manager UI and notifications |
| src/main/java/com/clbooster/app/views/NotificationsView.java | Localized notifications UI |
| src/main/java/com/clbooster/app/views/HelpView.java | Localized help/FAQ/support UI |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| notifications.earlier=Earlier | ||
| notifications.aiGenerated=AI Generated | ||
| notifications.coverLetterReady=Your cover letter is ready for review | ||
| notifications.optimizationComplete=Optimization Complete | ||
| notifications.scoreImproved=Your match score has improved | ||
| notifications.documentExported=Document Exported | ||
| notifications.exportedAsPDF=Your document was exported as PDF | ||
| notifications.newFeature=New Feature Available | ||
| notifications.tryToneCustomization=Try tone customization for your cover letters | ||
| notifications.welcome=Welcome to CL Booster | ||
| notifications.getStarted=Get started by creating your first cover letter | ||
| notifications.allRead=All notifications marked as read |
There was a problem hiding this comment.
notifications.* keys are defined twice (e.g., notifications.stayUpdated, notifications.all, etc.). In Java .properties files the later definition silently overrides the earlier one, which is error-prone and makes future edits confusing. Remove the duplicate block so each key is defined exactly once.
| notifications.earlier=Earlier | |
| notifications.aiGenerated=AI Generated | |
| notifications.coverLetterReady=Your cover letter is ready for review | |
| notifications.optimizationComplete=Optimization Complete | |
| notifications.scoreImproved=Your match score has improved | |
| notifications.documentExported=Document Exported | |
| notifications.exportedAsPDF=Your document was exported as PDF | |
| notifications.newFeature=New Feature Available | |
| notifications.tryToneCustomization=Try tone customization for your cover letters | |
| notifications.welcome=Welcome to CL Booster | |
| notifications.getStarted=Get started by creating your first cover letter | |
| notifications.allRead=All notifications marked as read |
| notifications.earlier=更早 | ||
| notifications.aiGenerated=AI生成 | ||
| notifications.coverLetterReady=您的求职信已准备好审核 | ||
| notifications.optimizationComplete=优化完成 | ||
| notifications.scoreImproved=您的匹配分数已提高 | ||
| notifications.documentExported=文档已导出 | ||
| notifications.exportedAsPDF=您的文档已导出为PDF | ||
| notifications.newFeature=新功能可用 | ||
| notifications.tryToneCustomization=尝试为您的求职信使用语气自定义 | ||
| notifications.welcome=欢迎使用CL Booster | ||
| notifications.getStarted=通过创建您的第一封求职信开始 | ||
| notifications.allRead=所有通知已标记为已读 |
There was a problem hiding this comment.
notifications.* translations are duplicated (same keys repeated starting again at notifications.stayUpdated). Duplicate keys in .properties are silently overridden and make the file harder to maintain—please delete the repeated block so each key appears once.
| notifications.earlier=更早 | |
| notifications.aiGenerated=AI生成 | |
| notifications.coverLetterReady=您的求职信已准备好审核 | |
| notifications.optimizationComplete=优化完成 | |
| notifications.scoreImproved=您的匹配分数已提高 | |
| notifications.documentExported=文档已导出 | |
| notifications.exportedAsPDF=您的文档已导出为PDF | |
| notifications.newFeature=新功能可用 | |
| notifications.tryToneCustomization=尝试为您的求职信使用语气自定义 | |
| notifications.welcome=欢迎使用CL Booster | |
| notifications.getStarted=通过创建您的第一封求职信开始 | |
| notifications.allRead=所有通知已标记为已读 |
| dashboard.coverLetters=Kirjeet | ||
| dashboard.allTimeGenerated=Kaikki luodut | ||
| dashboard.resumesUploaded=Ladatut ansioluettelot | ||
| dashboard.storedOnAccount=Tilillä | ||
| dashboard.thisWeek=Tällä viikolla | ||
| dashboard.lettersGenerated2=Kirjeitä luotu |
There was a problem hiding this comment.
These dashboard.* strings in the default (English) bundle are in Finnish (e.g., Kirjeet, Kaikki luodut, etc.). This will surface Finnish UI text when the locale is English. Replace these values with English equivalents and keep the Finnish versions in messages_fi.properties.
| dashboard.coverLetters=Kirjeet | |
| dashboard.allTimeGenerated=Kaikki luodut | |
| dashboard.resumesUploaded=Ladatut ansioluettelot | |
| dashboard.storedOnAccount=Tilillä | |
| dashboard.thisWeek=Tällä viikolla | |
| dashboard.lettersGenerated2=Kirjeitä luotu | |
| dashboard.coverLetters=Cover Letters | |
| dashboard.allTimeGenerated=All-time generated | |
| dashboard.resumesUploaded=Resumes uploaded | |
| dashboard.storedOnAccount=Stored on account | |
| dashboard.thisWeek=This week | |
| dashboard.lettersGenerated2=Letters generated |
| return translationService.translate("dashboard.justNow"); | ||
| if (hours < 24) | ||
| return hours + "h ago"; | ||
| return hours + translationService.translate("dashboard.hoursAgo"); | ||
| long days = hours / 24; | ||
| if (days == 1) | ||
| return "Yesterday"; | ||
| return translationService.translate("dashboard.yesterday"); | ||
| if (days < 7) | ||
| return days + " days ago"; | ||
| return days + translationService.translate("dashboard.daysAgo"); | ||
| if (days < 30) | ||
| return (days / 7) + " weeks ago"; | ||
| return (days / 30) + " months ago"; | ||
| return (days / 7) + translationService.translate("dashboard.weeksAgo"); | ||
| return (days / 30) + translationService.translate("dashboard.monthsAgo"); |
There was a problem hiding this comment.
Relative time formatting concatenates the number directly with the translated suffix (e.g., hours + translate("dashboard.hoursAgo")), which produces strings like 2hours ago for English. Add appropriate spacing/formatting (either in code or by including the leading space in the translation) and ensure weeks/months use the same approach.
| serveDownload(bytes, mimeType, file.getName()); | ||
| } catch (IOException ex) { | ||
| Notification.show("Error reading file: " + ex.getMessage(), 3000, Notification.Position.TOP_CENTER); | ||
| Notification.show(translationService.translate("history.fileNotFound", ex.getMessage()), 3000, |
There was a problem hiding this comment.
In the IOException path you display history.fileNotFound with the exception message. That produces misleading UX (read/IO error != file missing) and also reuses the wrong translation key. Add a dedicated key (e.g., history.errorReading=Error reading file: {0}) and use it here.
| Notification.show(translationService.translate("history.fileNotFound", ex.getMessage()), 3000, | |
| Notification.show(translationService.translate("history.errorReading", ex.getMessage()), 3000, |
| resumeSelect.getStyle().set("flex", "1").set("min-width", "0"); | ||
| resumeSelect.getElement().setAttribute("title", "Select a saved resume"); | ||
| resumeSelect.getElement().setAttribute("title", | ||
| translationService.translate("generator.step2.selectSavedResume")); |
There was a problem hiding this comment.
generator.step2.selectSavedResume is referenced for the select tooltip, but this key does not exist in the message bundles (at least not in messages.properties). Add the key to all bundles (or reuse an existing key) so users don’t see a raw key/fallback text.
| translationService.translate("generator.step2.selectSavedResume")); | |
| translationService.translate("generator.step2.savedResumes")); |
| TEXT_PRIMARY)); | ||
| summary.add(createSummaryRow("generator.step4.company", companyName.isEmpty() ? "Apple Inc." : companyName, | ||
| TEXT_PRIMARY)); | ||
| summary.add(createSummaryRow("generator.step4.tone", selectedTone, TEXT_PRIMARY)); |
There was a problem hiding this comment.
selectedTone now stores an internal tone id (e.g., professional/creative/storyteller), but Step 4 displays it directly. This will show the raw id instead of a localized label. Map the id to the appropriate translation key (e.g., generator.tone.professional) when rendering the summary (and anywhere else it’s shown).
| summary.add(createSummaryRow("generator.step4.tone", selectedTone, TEXT_PRIMARY)); | |
| String toneKey = (selectedTone == null || selectedTone.isEmpty()) | |
| ? null | |
| : "generator.tone." + selectedTone; | |
| String toneLabel = toneKey == null ? "" : translationService.translate(toneKey); | |
| summary.add(createSummaryRow("generator.step4.tone", toneLabel, TEXT_PRIMARY)); |
| settings.preferencesDesc=Gereencie sua experiência de candidatura e acessibilidade | ||
| settings.languageInterface=Idioma | ||
| settings.languageSelect=Selecione seu idioma preferido para a interface e geração de IA. | ||
| settings.notificationsManage=Gere quando e como você recebe atualizações de nós. |
There was a problem hiding this comment.
Portuguese translations contain typos/grammar issues here (e.g., Gereencie → Gerencie, and Gere quando is awkward/incorrect in this context). Please correct these strings so the UI reads naturally in Portuguese.
| settings.preferencesDesc=Gereencie sua experiência de candidatura e acessibilidade | |
| settings.languageInterface=Idioma | |
| settings.languageSelect=Selecione seu idioma preferido para a interface e geração de IA. | |
| settings.notificationsManage=Gere quando e como você recebe atualizações de nós. | |
| settings.preferencesDesc=Gerencie sua experiência de candidatura e acessibilidade | |
| settings.languageInterface=Idioma | |
| settings.languageSelect=Selecione seu idioma preferido para a interface e geração de IA. | |
| settings.notificationsManage=Gerencie quando e como você recebe nossas atualizações. |
| notifications.stayUpdated=Pysy ajan tasalla viimeisimmistä toimistasi | ||
| notifications.all=Kaikki | ||
| notifications.unread=Lukemattomat | ||
| notifications.mentions=Maininnat | ||
| notifications.today=Tänään | ||
| notifications.yesterday=Eilen | ||
| notifications.earlier=Aiemmin | ||
| notifications.aiGenerated=AI-generoitu | ||
| notifications.coverLetterReady=Ansioluettelosi on valmis tarkistettavaksi | ||
| notifications.optimizationComplete=Optimointi valmis | ||
| notifications.scoreImproved=Vastaavuuspisteesi on parantunut | ||
| notifications.documentExported=Asiakirja viety | ||
| notifications.exportedAsPDF=Asiakirjasi on viety PDF-muodossa | ||
| notifications.newFeature=Uusi ominaisuus saatavilla | ||
| notifications.tryToneCustomization=Kokeile sävyn mukauttamista ansioluetteloillesi | ||
| notifications.welcome=Tervetuloa CL Boosteriin | ||
| notifications.getStarted=Aloita luomalla ensimmäinen ansioluettelosi | ||
| notifications.allRead=Kaikki ilmoitukset merkitty luetuiksi |
There was a problem hiding this comment.
notifications.* keys are duplicated (the block starts again at notifications.stayUpdated on line 170). Duplicate keys in .properties are silently overridden and make maintaining translations difficult. Remove the repeated definitions so each key is defined once.
| notifications.stayUpdated=Pysy ajan tasalla viimeisimmistä toimistasi | |
| notifications.all=Kaikki | |
| notifications.unread=Lukemattomat | |
| notifications.mentions=Maininnat | |
| notifications.today=Tänään | |
| notifications.yesterday=Eilen | |
| notifications.earlier=Aiemmin | |
| notifications.aiGenerated=AI-generoitu | |
| notifications.coverLetterReady=Ansioluettelosi on valmis tarkistettavaksi | |
| notifications.optimizationComplete=Optimointi valmis | |
| notifications.scoreImproved=Vastaavuuspisteesi on parantunut | |
| notifications.documentExported=Asiakirja viety | |
| notifications.exportedAsPDF=Asiakirjasi on viety PDF-muodossa | |
| notifications.newFeature=Uusi ominaisuus saatavilla | |
| notifications.tryToneCustomization=Kokeile sävyn mukauttamista ansioluetteloillesi | |
| notifications.welcome=Tervetuloa CL Boosteriin | |
| notifications.getStarted=Aloita luomalla ensimmäinen ansioluettelosi | |
| notifications.allRead=Kaikki ilmoitukset merkitty luetuiksi |
| generator.step4.description=Coletamos tudo o que precisamos para construir sua carta de apresentação perfeita. | ||
| generator.step4.role=Cargo: | ||
| generator.step4.company=Empresa: | ||
| generator.step4.tone=Tono: |
There was a problem hiding this comment.
Typo in Portuguese translation: generator.step4.tone=Tono: should be Tom: (tone).
| generator.step4.tone=Tono: | |
| generator.step4.tone=Tom: |
This pull request introduces significant improvements to the application's internationalization (i18n) by expanding supported languages and refactoring UI components to use translation keys throughout the dashboard and generator wizard views. The changes enhance the user experience for a broader audience and make the UI text fully translatable.
Internationalization and Language Support:
TranslationService. Updated language parsing logic to match the new supported languages. [1] [2]UI Refactoring for Translatability:
DashboardViewto useTranslationServicefor all user-facing strings, including headings, button labels, section titles, quick actions, and relative date formatting. This ensures all dashboard text is translatable. [1] [2] [3] [4] [5] [6] [7] [8] [9]GeneratorWizardViewto inject and useTranslationServicefor step titles, descriptions, form field labels/placeholders, and navigation buttons, making the generator wizard fully translatable. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]