mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-01-09 19:58:05 -05:00
feat: enhance language selection message and add translation contribution link
This commit is contained in:
@@ -312,7 +312,8 @@
|
||||
"reset": "Reset",
|
||||
"reset_to_default": "Reset to default",
|
||||
"profile_picture_has_been_reset": "Profile picture has been reset. It may take a few minutes to update.",
|
||||
"select_the_language_you_want_to_use": "Select the language you want to use. Some languages may not be fully translated.",
|
||||
"select_the_language_you_want_to_use": "Select the language you want to use. Please note that some text may be automatically translated and could be inaccurate.",
|
||||
"contribute_to_translation": "If you find an issue you're welcome to contribute to the translation on <link href='https://crowdin.com/project/pocket-id'>Crowdin</link>.",
|
||||
"personal": "Personal",
|
||||
"global": "Global",
|
||||
"all_users": "All Users",
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
{description}
|
||||
{#if docsLink}
|
||||
<a
|
||||
class="relative text-white after:absolute after:bottom-0 after:left-0 after:h-px after:w-full after:translate-y-[-1px] after:bg-white"
|
||||
class="relative text-black after:absolute after:bottom-0 after:left-0 after:h-px after:w-full after:translate-y-[-1px] after:bg-white dark:text-white"
|
||||
href={docsLink}
|
||||
target="_blank"
|
||||
>
|
||||
@@ -72,7 +72,7 @@
|
||||
{/if}
|
||||
{/if}
|
||||
{#if input?.error}
|
||||
<p class="text-destructive mt-1 text-xs text-start">{input.error}</p>
|
||||
<p class="text-destructive mt-1 text-start text-xs">{input.error}</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
83
frontend/src/lib/components/formatted-message.svelte
Normal file
83
frontend/src/lib/components/formatted-message.svelte
Normal file
@@ -0,0 +1,83 @@
|
||||
<!-- Component to display messages from Paraglide with support for links in the format <link href="url">text</link>. -->
|
||||
<!-- This gets redundant in the future, because the library will support this natively. https://github.com/opral/inlang-sdk/issues/240 -->
|
||||
<script lang="ts">
|
||||
let {
|
||||
m
|
||||
}: {
|
||||
m: string;
|
||||
} = $props();
|
||||
|
||||
interface MessagePart {
|
||||
type: 'text' | 'link';
|
||||
content: string;
|
||||
href?: string;
|
||||
}
|
||||
|
||||
function parseMessage(content: string): MessagePart[] | string {
|
||||
// Regex to match only <link href="url">text</link> format
|
||||
const linkRegex = /<link\s+href=(['"])(.*?)\1>(.*?)<\/link>/g;
|
||||
|
||||
if (!linkRegex.test(content)) {
|
||||
return content;
|
||||
}
|
||||
|
||||
// Reset regex lastIndex for reuse
|
||||
linkRegex.lastIndex = 0;
|
||||
|
||||
const parts: MessagePart[] = [];
|
||||
let lastIndex = 0;
|
||||
let match;
|
||||
|
||||
while ((match = linkRegex.exec(content)) !== null) {
|
||||
// Add text before the link
|
||||
if (match.index > lastIndex) {
|
||||
const textContent = content.slice(lastIndex, match.index);
|
||||
if (textContent) {
|
||||
parts.push({ type: 'text', content: textContent });
|
||||
}
|
||||
}
|
||||
|
||||
const href = match[2];
|
||||
const linkText = match[3];
|
||||
|
||||
parts.push({
|
||||
type: 'link',
|
||||
content: linkText,
|
||||
href: href
|
||||
});
|
||||
|
||||
lastIndex = match.index + match[0].length;
|
||||
}
|
||||
|
||||
// Add remaining text after the last link
|
||||
if (lastIndex < content.length) {
|
||||
const remainingText = content.slice(lastIndex);
|
||||
if (remainingText) {
|
||||
parts.push({ type: 'text', content: remainingText });
|
||||
}
|
||||
}
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
const parsedContent = parseMessage(m);
|
||||
</script>
|
||||
|
||||
{#if typeof parsedContent === 'string'}
|
||||
{parsedContent}
|
||||
{:else}
|
||||
{#each parsedContent as part}
|
||||
{#if part.type === 'text'}
|
||||
{part.content}
|
||||
{:else if part.type === 'link'}
|
||||
<a
|
||||
class="text-black underline dark:text-white"
|
||||
href={part.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{part.content}
|
||||
</a>
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
@@ -13,7 +13,7 @@
|
||||
<p
|
||||
bind:this={ref}
|
||||
data-slot="card-description"
|
||||
class={cn('text-muted-foreground text-sm', className)}
|
||||
class={cn('text-muted-foreground text-sm mt-1', className)}
|
||||
{...restProps}
|
||||
>
|
||||
{@render children?.()}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import FormattedMessage from '$lib/components/formatted-message.svelte';
|
||||
import * as Alert from '$lib/components/ui/alert';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
@@ -9,7 +10,6 @@
|
||||
import type { Passkey } from '$lib/types/passkey.type';
|
||||
import type { UserCreate } from '$lib/types/user.type';
|
||||
import { axiosErrorToast, getWebauthnErrorMessage } from '$lib/utils/error-util';
|
||||
import { startRegistration } from '@simplewebauthn/browser';
|
||||
import {
|
||||
KeyRound,
|
||||
Languages,
|
||||
@@ -17,6 +17,7 @@
|
||||
RectangleEllipsis,
|
||||
UserCog
|
||||
} from '@lucide/svelte';
|
||||
import { startRegistration } from '@simplewebauthn/browser';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import AccountForm from './account-form.svelte';
|
||||
import LocalePicker from './locale-picker.svelte';
|
||||
@@ -141,7 +142,7 @@
|
||||
|
||||
<!-- Passkey management card -->
|
||||
<div>
|
||||
<Card.Root>
|
||||
<Card.Root class="gap-3">
|
||||
<Card.Header>
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
@@ -200,6 +201,8 @@
|
||||
</Card.Title>
|
||||
<Card.Description>
|
||||
{m.select_the_language_you_want_to_use()}
|
||||
<br />
|
||||
<FormattedMessage m={m.contribute_to_translation()} />
|
||||
</Card.Description>
|
||||
</div>
|
||||
<LocalePicker />
|
||||
|
||||
Reference in New Issue
Block a user