feat: Rename to Toju and add translation
Some checks failed
Deploy Web Apps / deploy (push) Successful in 5m52s
Build Android APK / build-android-apk (push) Failing after 23m15s
Queue Release Build / prepare (push) Successful in 1m42s
Queue Release Build / build-linux (push) Failing after 9m33s
Queue Release Build / build-windows (push) Successful in 26m5s
Queue Release Build / finalize (push) Has been skipped

This commit is contained in:
2026-06-05 17:13:03 +02:00
parent 8ecfc9a1fe
commit ee293d7daf
301 changed files with 8247 additions and 2218 deletions

View File

@@ -29,6 +29,7 @@ import {
lucideChevronDown
} from '@ng-icons/lucide';
import { AppI18nService, APP_TRANSLATE_IMPORTS } from '../../../../core/i18n';
import { RoomsActions } from '../../../../store/rooms/rooms.actions';
import {
selectSearchResults,
@@ -91,7 +92,8 @@ export interface ServerDiscoverySection {
ChatMessageMarkdownComponent,
ConfirmDialogComponent,
LeaveServerDialogComponent,
ModalBackdropComponent
ModalBackdropComponent,
...APP_TRANSLATE_IMPORTS
],
viewProviders: [
provideIcons({
@@ -116,20 +118,81 @@ export class ServerBrowserComponent implements OnInit {
private pluginRequirements = inject(PluginRequirementService);
private pluginStore = inject(PluginStoreService);
private injector = inject(Injector);
private readonly i18n = inject(AppI18nService);
private searchSubject = new Subject<string>();
private banLookupRequestVersion = 0;
/** Discovery sections shown when the search query is empty. */
@Input() discoverySections: ServerDiscoverySection[] = [];
/** Title for the onboarding empty state when there is nothing to show. */
@Input() emptyStateTitle = 'No servers yet';
@Input() emptyStateTitle?: string;
/** Supporting copy for the onboarding empty state. */
@Input() emptyStateMessage = 'Search to find a server to join.';
@Input() emptyStateMessage?: string;
/** Placeholder for the search input. */
@Input() searchPlaceholder = 'Search servers...';
@Input() searchPlaceholder?: string;
/** Whether the My Servers quick bar is shown. */
@Input() showMyServers = true;
get resolvedEmptyStateTitle(): string {
return this.emptyStateTitle ?? this.i18n.instant('servers.browser.empty.title');
}
get resolvedEmptyStateMessage(): string {
return this.emptyStateMessage ?? this.i18n.instant('servers.browser.empty.message');
}
get resolvedSearchPlaceholder(): string {
return this.searchPlaceholder ?? this.i18n.instant('servers.browser.search.placeholder');
}
serverCardTitle(server: ServerInfo): string {
return this.isJoinedServer(server)
? this.i18n.instant('servers.browser.card.doubleClickOpen', { name: server.name })
: this.i18n.instant('servers.browser.card.doubleClickJoin', { name: server.name });
}
serverActionsLabel(server: ServerInfo): string {
return this.i18n.instant('servers.browser.card.serverActions', { name: server.name });
}
joinServerLabel(server: ServerInfo): string {
return this.i18n.instant('servers.browser.card.joinServer', { name: server.name });
}
ownerLabel(server: ServerInfo): string {
return this.i18n.instant('servers.browser.card.owner', { name: this.getServerOwnerLabel(server) });
}
bannedDialogMessage(): string {
return this.i18n.instant('servers.browser.bannedDialog.message', {
name: this.bannedServerName() || this.i18n.instant('servers.browser.bannedDialog.thisServer')
});
}
passwordDialogMessage(server: ServerInfo): string {
return this.i18n.instant('servers.browser.passwordDialog.message', { name: server.name });
}
pluginUsesPluginsLabel(serverName: string): string {
return this.i18n.instant('servers.plugins.usesPlugins', { name: serverName });
}
pluginConsentConfirmLabel(requiredCount: number): string {
if (this.pluginConsentBusy()) {
return this.i18n.instant('servers.plugins.downloading');
}
return requiredCount > 0
? this.i18n.instant('servers.plugins.acceptAndJoin')
: this.i18n.instant('servers.plugins.join');
}
pluginReadmeButtonLabel(pluginId: string): string {
return this.pluginConsentReadmeLoadingId() === pluginId
? this.i18n.instant('common.labels.loading')
: this.i18n.instant('servers.plugins.readme');
}
searchQuery = '';
searchResults = this.store.selectSignal(selectSearchResults);
isSearching = this.store.selectSignal(selectIsSearching);
@@ -340,7 +403,7 @@ export class ServerBrowserComponent implements OnInit {
this.selectedOptionalPluginIds.set(new Set());
this.closePluginConsentReadme();
} catch (error) {
this.pluginConsentError.set(error instanceof Error ? error.message : 'Unable to install server plugins');
this.pluginConsentError.set(error instanceof Error ? error.message : this.i18n.instant('servers.errors.installPluginsFailed'));
} finally {
this.pluginConsentBusy.set(false);
}
@@ -355,7 +418,7 @@ export class ServerBrowserComponent implements OnInit {
this.pluginConsentReadme.set(readme);
} catch (error) {
this.pluginConsentReadmeError.set(error instanceof Error ? error.message : 'Unable to load plugin readme');
this.pluginConsentReadmeError.set(error instanceof Error ? error.message : this.i18n.instant('servers.errors.loadPluginReadmeFailed'));
} finally {
this.pluginConsentReadmeLoadingId.set(null);
}
@@ -416,7 +479,7 @@ export class ServerBrowserComponent implements OnInit {
const ownerKey = server.ownerId || joinedRoom?.hostId || '';
const ownerMember = joinedRoom?.members?.find((member) => member.id === ownerKey || member.oderId === ownerKey);
return server.ownerName || ownerMember?.displayName || server.ownerId || joinedRoom?.hostId || 'Unknown owner';
return server.ownerName || ownerMember?.displayName || server.ownerId || joinedRoom?.hostId || this.i18n.instant('servers.browser.ownerUnknown');
}
private openJoinedRoom(room: Room): void {
@@ -457,7 +520,7 @@ export class ServerBrowserComponent implements OnInit {
roomId: server.id,
userId: currentUserId,
userPublicKey: currentUser?.oderId || currentUserId,
displayName: currentUser?.displayName || 'Anonymous',
displayName: currentUser?.displayName || this.i18n.instant('common.labels.anonymous'),
password: password?.trim() || undefined
},
{
@@ -503,7 +566,7 @@ export class ServerBrowserComponent implements OnInit {
error?: { error?: string; errorCode?: string };
};
const errorCode = serverError?.error?.errorCode;
const message = serverError?.error?.error || 'Failed to join server';
const message = serverError?.error?.error || this.i18n.instant('servers.errors.joinFailed');
if (errorCode === 'PASSWORD_REQUIRED') {
this.passwordPromptServer.set(server);
@@ -583,7 +646,7 @@ export class ServerBrowserComponent implements OnInit {
try {
await firstValueFrom(this.webrtc.connectToSignalingServer(wsUrl));
this.webrtc.identify(currentUser.oderId || currentUser.id, currentUser.displayName || 'User', wsUrl, {
this.webrtc.identify(currentUser.oderId || currentUser.id, currentUser.displayName || this.i18n.instant('common.labels.user'), wsUrl, {
description: currentUser.description,
profileUpdatedAt: currentUser.profileUpdatedAt,
homeSignalServerUrl: currentUser.homeSignalServerUrl