-
Notifications
You must be signed in to change notification settings - Fork 4k
Add translations on core views #13895
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
base: main
Are you sure you want to change the base?
Conversation
🚀 Preview Environment Ready! Your preview environment is available at: http://bore.pub:39452 This environment will automatically shut down when the PR is closed or after 5 hours. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Greptile Summary
This PR implements internationalization (i18n) support for core view names in Twenty, addressing issue #11999 where view names like 'All Tasks', 'All Companies', and 'Timeline' were not being translated for non-English users. The implementation follows a systematic approach across multiple layers of the application:
Database Layer Changes: A new isCustom
boolean field is added to the core.view
table through a TypeORM migration, defaulting to false
for existing views. This field distinguishes between system-generated core views and user-created custom views.
Backend Infrastructure: The View entity, DTO, and service are updated to support the new field. The ViewService automatically marks newly created views with isCustom: true
, while the prefill system handles core views appropriately.
Translation Implementation: Core view definition files are systematically updated to use the msg
macro from @lingui/core/macro
, wrapping hardcoded English strings like 'All Companies', 'All People', 'By Status', etc. in translatable template literals with fallback patterns (msg
string.message ?? ''
).
GraphQL Resolver Enhancement: A new field resolver is implemented that conditionally translates view names - custom views return their original user-provided names unchanged, while core views are processed through the i18n system using generateMessageId
for translation key generation.
Frontend Schema Updates: The generated GraphQL types file reflects the new isCustom
field in the CoreView
type definition.
The solution integrates with Twenty's existing Lingui-based translation pipeline, ensuring that core view names can be extracted for translation through Crowdin while preserving the integrity of user-defined custom view names. This enables the application to display properly localized view names for system views across all supported languages.
Confidence score: 4/5
- This PR is safe to merge with good implementation of internationalization patterns
- Score reflects solid architecture with proper separation of concerns between custom and core views, though the GraphQL resolver approach adds some complexity
- Pay close attention to view.resolver.ts and the migration file for potential runtime issues
Context used:
Rule - Use lingui for all user-facing strings to make them translatable, including field type labels and UI text. (link)
20 files reviewed, 2 comments
} | ||
|
||
const messageId = generateMessageId(view.name); | ||
const translatedMessage = i18n._(messageId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: The global i18n._()
call may not respect the user's current locale since no locale context is passed. Consider using the context parameter to get user-specific locale.
...rc/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-by-stage.view.ts
Outdated
Show resolved
Hide resolved
...erver/src/engine/workspace-manager/standard-objects-prefill-data/views/companies-all.view.ts
Outdated
Show resolved
Hide resolved
...twenty-server/src/database/typeorm/core/migrations/common/1755075898674-AddIsCustomToView.ts
Show resolved
Hide resolved
@@ -109,7 +109,10 @@ export class ViewService { | |||
); | |||
} | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not try it, but does it behave well for newly created views on custom objects? If I'm spanish and create a custom object, will the default view be named properly and not with "all"? Maybe it's already the case! Is that view Standard then? It seems like that view should not be considered custom also, is that the case?
0205037
to
1e62e77
Compare
@greptileai trigger |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Greptile Summary
This review covers only the changes made since the last review (commit 5a88ea0), not the entire PR.
The most recent changes focus on completing the internationalization implementation for core views. The key modifications include:
-
Database Migration: Added a new migration (
1755075898674-AddIsCustomToView.ts
) that introduces anisCustom
boolean field to the core.view table with a default value of false. This field is crucial for distinguishing between system-provided core views (which should be translated) and user-created custom views (which should retain their original names). -
Entity and DTO Updates: The View entity (
view.entity.ts
) now includes theisCustom
field as a required boolean column, while the generated GraphQL types (graphql.ts
) reflect this schema change with the newisCustom
property in theCoreView
type. -
Translation Infrastructure: Several view definition files have been updated to use lingui's
msg
macro for translatable strings, including workflow-related views (workflows-all.view.ts
,workflow-runs-all.view.ts
,workflow-versions-all.view.ts
) and core object views (companies-all.view.ts
,people-all.view.ts
,opportunities-all.view.ts
,notes-all.view.ts
). -
Resolver Enhancement: The
view.resolver.ts
now includes a sophisticated name resolution system that handles translation for core views while preserving custom view names. It supports both simple translations and template-based view names with{{objectLabelPlural}}
placeholders. -
Service Layer Updates: The ViewService has been refactored with comprehensive CRUD operations and proper validation, while the ViewSyncService includes special handling for custom object INDEX views using translatable templates.
These changes work together to address the original issue where view names like 'All Tasks', 'All Companies' remained untranslated in non-English locales, while maintaining backward compatibility and user autonomy over custom view naming.
Confidence score: 4/5
- This PR introduces significant changes to the translation system but follows established patterns and includes proper database migrations
- Score reflects the complexity of the i18n implementation and potential edge cases around fallback behavior and template replacement
- Pay close attention to the view resolver logic and migration files to ensure proper handling of existing data
22 files reviewed, 8 comments
...r/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-runs-all.view.ts
Outdated
Show resolved
Hide resolved
...erver/src/engine/workspace-manager/standard-objects-prefill-data/views/workflows-all.view.ts
Outdated
Show resolved
Hide resolved
...c/engine/workspace-manager/standard-objects-prefill-data/views/workflow-versions-all.view.ts
Outdated
Show resolved
Hide resolved
...rc/engine/workspace-manager/standard-objects-prefill-data/constants/view-prefix.constants.ts
Outdated
Show resolved
Hide resolved
...r/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunities-all.view.ts
Outdated
Show resolved
Hide resolved
...y-server/src/engine/workspace-manager/standard-objects-prefill-data/views/custom-all.view.ts
Outdated
Show resolved
Hide resolved
packages/twenty-server/src/modules/view/services/view-sync.service.ts
Outdated
Show resolved
Hide resolved
...erver/src/engine/workspace-manager/standard-objects-prefill-data/views/companies-all.view.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not a custom view, probably should rename it to something more appropriate -- something like --
customObject-all.view.ts ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
casing doesn't feel right in the proposed solution but agree with the comment!
} | ||
|
||
if (view.name.includes('{{objectLabelPlural}}')) { | ||
const objectMetadata = await this.viewService.getObjectMetadataByViewId( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Efficiency issue (N queries)
packages/twenty-server/src/engine/core-modules/view/resolvers/view.resolver.ts
Outdated
Show resolved
Hide resolved
📊 API Changes ReportREST Metadata API Analysis ErrorError Output
|
#: src/engine/workspace-manager/standard-objects-prefill-data/views/custom-all.view.ts | ||
#: src/engine/workspace-manager/standard-objects-prefill-data/views/companies-all.view.ts | ||
msgid "All {objectLabelPlural}" | ||
msgstr "{objectLabelPlural}すべて" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -91,7 +91,7 @@ const createWorkspaceViews = async ( | |||
kanbanAggregateOperationFieldMetadataId, | |||
}) => ({ | |||
id, | |||
name, | |||
name: name.message ?? '', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is wrong we shouldnt have message decriptor here
nor should we use template for workspace views -- not sure whats the best here -- I think just seperate views for now should do -- and we will get rid of them when we get rid of this file?
closes #11999