Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 6 additions & 145 deletions apps/web/lib/i18n/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,217 +130,78 @@ export const appLanguages = [
code: "en-US",
label: {
"en-US": "English (US)",
"de-DE": "Englisch (US)",
"pt-BR": "Inglês (EUA)",
"fr-FR": "Anglais (États-Unis)",
"zh-Hant-TW": "英文 (美國)",
"pt-PT": "Inglês (EUA)",
"ro-RO": "Engleză (SUA)",
"ja-JP": "英語(米国)",
"zh-Hans-CN": "英语(美国)",
"nl-NL": "Engels (VS)",
"es-ES": "Inglés (EE.UU.)",
"sv-SE": "Engelska (USA)",
"ru-RU": "Английский (США)",
},
},
{
code: "de-DE",
label: {
"en-US": "German",
"de-DE": "Deutsch",
"pt-BR": "Alemão",
"fr-FR": "Allemand",
"zh-Hant-TW": "德語",
"pt-PT": "Alemão",
"ro-RO": "Germană",
"ja-JP": "ドイツ語",
"zh-Hans-CN": "德语",
"nl-NL": "Duits",
"es-ES": "Alemán",
"sv-SE": "Tyska",
"ru-RU": "Немецкий",
},
},
{
code: "pt-BR",
label: {
"en-US": "Portuguese (Brazil)",
"de-DE": "Portugiesisch (Brasilien)",
"pt-BR": "Português (Brasil)",
"fr-FR": "Portugais (Brésil)",
"zh-Hant-TW": "葡萄牙語 (巴西)",
"pt-PT": "Português (Brasil)",
"ro-RO": "Portugheză (Brazilia)",
"ja-JP": "ポルトガル語(ブラジル)",
"zh-Hans-CN": "葡萄牙语(巴西)",
"nl-NL": "Portugees (Brazilië)",
"es-ES": "Portugués (Brasil)",
"sv-SE": "Portugisiska (Brasilien)",
"ru-RU": "Португальский (Бразилия)",
},
},
{
code: "fr-FR",
label: {
"en-US": "French",
"de-DE": "Französisch",
"pt-BR": "Francês",
"fr-FR": "Français",
"zh-Hant-TW": "法語",
"pt-PT": "Francês",
"ro-RO": "Franceză",
"ja-JP": "フランス語",
"zh-Hans-CN": "法语",
"nl-NL": "Frans",
"es-ES": "Francés",
"sv-SE": "Franska",
"ru-RU": "Французский",
},
},
{
code: "zh-Hant-TW",
label: {
"en-US": "Chinese (Traditional)",
"de-DE": "Chinesisch (Traditionell)",
"pt-BR": "Chinês (Tradicional)",
"fr-FR": "Chinois (Traditionnel)",
"zh-Hant-TW": "繁體中文",
"pt-PT": "Chinês (Tradicional)",
"ro-RO": "Chineza (Tradițională)",
"ja-JP": "中国語(繁体字)",
"zh-Hans-CN": "繁体中文",
"nl-NL": "Chinees (Traditioneel)",
"es-ES": "Chino (Tradicional)",
"sv-SE": "Kinesiska (traditionell)",
"ru-RU": "Китайский (традиционный)",
},
},
{
code: "pt-PT",
label: {
"en-US": "Portuguese (Portugal)",
"de-DE": "Portugiesisch (Portugal)",
"pt-BR": "Português (Portugal)",
"fr-FR": "Portugais (Portugal)",
"zh-Hant-TW": "葡萄牙語 (葡萄牙)",
"pt-PT": "Português (Portugal)",
"ro-RO": "Portugheză (Portugalia)",
"ja-JP": "ポルトガル語(ポルトガル)",
"zh-Hans-CN": "葡萄牙语(葡萄牙)",
"nl-NL": "Portugees (Portugal)",
"es-ES": "Portugués (Portugal)",
"sv-SE": "Portugisiska (Portugal)",
"ru-RU": "Португальский (Португалия)",
},
},
{
code: "ro-RO",
label: {
"en-US": "Romanian",
"de-DE": "Rumänisch",
"pt-BR": "Romeno",
"fr-FR": "Roumain",
"zh-Hant-TW": "羅馬尼亞語",
"pt-PT": "Romeno",
"ro-RO": "Română",
"ja-JP": "ルーマニア語",
"zh-Hans-CN": "罗马尼亚语",
"nl-NL": "Roemeens",
"es-ES": "Rumano",
"sv-SE": "Rumänska",
"ru-RU": "Румынский",
},
},
{
code: "ja-JP",
label: {
"en-US": "Japanese",
"de-DE": "Japanisch",
"pt-BR": "Japonês",
"fr-FR": "Japonais",
"zh-Hant-TW": "日語",
"pt-PT": "Japonês",
"ro-RO": "Japoneză",
"ja-JP": "日本語",
"zh-Hans-CN": "日语",
"nl-NL": "Japans",
"es-ES": "Japonés",
"sv-SE": "Japanska",
"ru-RU": "Японский",
},
},
{
code: "zh-Hans-CN",
label: {
"en-US": "Chinese (Simplified)",
"de-DE": "Chinesisch (Vereinfacht)",
"pt-BR": "Chinês (Simplificado)",
"fr-FR": "Chinois (Simplifié)",
"zh-Hant-TW": "簡體中文",
"pt-PT": "Chinês (Simplificado)",
"ro-RO": "Chineza (Simplificată)",
"ja-JP": "中国語(簡体字)",
"zh-Hans-CN": "简体中文",
"nl-NL": "Chinees (Vereenvoudigd)",
"es-ES": "Chino (Simplificado)",
"sv-SE": "Kinesiska (förenklad)",
"ru-RU": "Китайский (упрощенный)",
},
},
{
code: "nl-NL",
label: {
"en-US": "Dutch",
"de-DE": "Niederländisch",
"pt-BR": "Holandês",
"fr-FR": "Néerlandais",
"zh-Hant-TW": "荷蘭語",
"pt-PT": "Holandês",
"ro-RO": "Olandeza",
"ja-JP": "オランダ語",
"zh-Hans-CN": "荷兰语",
"nl-NL": "Nederlands",
"es-ES": "Neerlandés",
"sv-SE": "Nederländska",
"ru-RU": "Голландский",
},
},
{
code: "es-ES",
label: {
"en-US": "Spanish",
"de-DE": "Spanisch",
"pt-BR": "Espanhol",
"fr-FR": "Espagnol",
"zh-Hant-TW": "西班牙語",
"pt-PT": "Espanhol",
"ro-RO": "Spaniol",
"ja-JP": "スペイン語",
"zh-Hans-CN": "西班牙语",
"nl-NL": "Spaans",
"es-ES": "Español",
"sv-SE": "Spanska",
"ru-RU": "Испанский",
},
},
{
code: "sv-SE",
label: {
"en-US": "Swedish",
"de-DE": "Schwedisch",
"pt-BR": "Sueco",
"fr-FR": "Suédois",
"zh-Hant-TW": "瑞典語",
"pt-PT": "Sueco",
"ro-RO": "Suedeză",
"ja-JP": "スウェーデン語",
"zh-Hans-CN": "瑞典语",
"nl-NL": "Zweeds",
"es-ES": "Sueco",
"sv-SE": "Svenska",
"ru-RU": "Шведский",
},
},
{
code: "ru-RU",
label: {
"en-US": "Russian",
},
},
];
export { iso639Languages };
3 changes: 1 addition & 2 deletions apps/web/lib/utils/locale.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,10 @@ describe("locale", () => {
// Verify sv-SE is in AVAILABLE_LOCALES
expect(AVAILABLE_LOCALES).toContain("sv-SE");

// Verify Swedish has a language entry with proper labels
// Verify Swedish has a language entry with proper label
const swedishLanguage = appLanguages.find((lang) => lang.code === "sv-SE");
expect(swedishLanguage).toBeDefined();
expect(swedishLanguage?.label["en-US"]).toBe("Swedish");
expect(swedishLanguage?.label["sv-SE"]).toBe("Svenska");

// Verify the locale can be matched from Accept-Language header
vi.mocked(nextHeaders.headers).mockReturnValue({
Expand Down
2 changes: 2 additions & 0 deletions docs/api-reference/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -5868,6 +5868,7 @@
"jpeg",
"jpg",
"webp",
"ico",
"pdf",
"eml",
"doc",
Expand All @@ -5883,6 +5884,7 @@
"avi",
"mkv",
"webm",
"mp3",
"zip",
"rar",
"7z",
Expand Down
4 changes: 4 additions & 0 deletions packages/survey-ui/src/components/elements/consent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export interface ConsentProps {
onChange: (checked: boolean) => void;
/** Whether the field is required (shows asterisk indicator) */
required?: boolean;
/** Custom label for the required indicator */
requiredLabel?: string;
/** Error message to display */
errorMessage?: string;
/** Text direction: 'ltr' (left-to-right), 'rtl' (right-to-left), or 'auto' (auto-detect from content) */
Expand All @@ -45,6 +47,7 @@ function Consent({
value = false,
onChange,
required = false,
requiredLabel,
errorMessage,
dir = "auto",
disabled = false,
Expand All @@ -63,6 +66,7 @@ function Consent({
headline={headline}
description={description}
required={required}
requiredLabel={requiredLabel}
htmlFor={inputId}
imageUrl={imageUrl}
videoUrl={videoUrl}
Expand Down
10 changes: 6 additions & 4 deletions packages/survey-ui/src/components/elements/cta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export interface CTAProps {
onClick: () => void;
/** Whether the field is required (shows asterisk indicator) */
required?: boolean;
/** Custom label for the required indicator */
requiredLabel?: string;
/** Error message to display */
errorMessage?: string;
/** Text direction: 'ltr' (left-to-right), 'rtl' (right-to-left), or 'auto' (auto-detect from content) */
Expand All @@ -50,6 +52,7 @@ function CTA({
buttonExternal = false,
onClick,
required = false,
requiredLabel,
errorMessage,
dir = "auto",
disabled = false,
Expand All @@ -73,6 +76,7 @@ function CTA({
headline={headline}
description={description}
required={required}
requiredLabel={requiredLabel}
htmlFor={inputId}
imageUrl={imageUrl}
videoUrl={videoUrl}
Expand All @@ -82,8 +86,7 @@ function CTA({
<div className="relative space-y-2">
<ElementError errorMessage={errorMessage} dir={dir} />

{buttonExternal && (
<div className="flex w-full justify-start">
{buttonExternal ? <div className="flex w-full justify-start">
<Button
id={inputId}
type="button"
Expand All @@ -94,8 +97,7 @@ function CTA({
{buttonLabel}
<SquareArrowOutUpRightIcon className="size-4" />
</Button>
</div>
)}
</div> : null}
</div>
</div>
);
Expand Down
4 changes: 4 additions & 0 deletions packages/survey-ui/src/components/elements/date.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ interface DateElementProps {
onChange: (value: string) => void;
/** Whether the field is required (shows asterisk indicator) */
required?: boolean;
/** Custom label for the required indicator */
requiredLabel?: string;
/** Minimum date allowed (ISO format: YYYY-MM-DD) */
minDate?: string;
/** Maximum date allowed (ISO format: YYYY-MM-DD) */
Expand All @@ -45,6 +47,7 @@ function DateElement({
value,
onChange,
required = false,
requiredLabel,
minDate,
maxDate,
dir = "auto",
Expand Down Expand Up @@ -152,6 +155,7 @@ function DateElement({
headline={headline}
description={description}
required={required}
requiredLabel={requiredLabel}
htmlFor={inputId}
imageUrl={imageUrl}
videoUrl={videoUrl}
Expand Down
4 changes: 4 additions & 0 deletions packages/survey-ui/src/components/elements/file-upload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ interface FileUploadProps {
allowedFileExtensions?: string[];
/** Whether the field is required (shows asterisk indicator) */
required?: boolean;
/** Custom label for the required indicator */
requiredLabel?: string;
/** Error message to display */
errorMessage?: string;
/** Whether the component is in uploading state */
Expand Down Expand Up @@ -219,6 +221,7 @@ function FileUpload({
allowMultiple = false,
allowedFileExtensions,
required = false,
requiredLabel,
errorMessage,
isUploading = false,
dir = "auto",
Expand Down Expand Up @@ -279,6 +282,7 @@ function FileUpload({
headline={headline}
description={description}
required={required}
requiredLabel={requiredLabel}
htmlFor={inputId}
imageUrl={imageUrl}
videoUrl={videoUrl}
Expand Down
4 changes: 4 additions & 0 deletions packages/survey-ui/src/components/elements/form-field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ interface FormFieldProps {
onChange: (value: Record<string, string>) => void;
/** Whether the entire form is required (shows asterisk indicator) */
required?: boolean;
/** Custom label for the required indicator */
requiredLabel?: string;
/** Error message to display */
errorMessage?: string;
/** Text direction: 'ltr' (left-to-right), 'rtl' (right-to-left), or 'auto' (auto-detect from content) */
Expand All @@ -57,6 +59,7 @@ function FormField({
value = {},
onChange,
required = false,
requiredLabel,
errorMessage,
dir = "auto",
disabled = false,
Expand Down Expand Up @@ -103,6 +106,7 @@ function FormField({
headline={headline}
description={description}
required={required}
requiredLabel={requiredLabel}
imageUrl={imageUrl}
videoUrl={videoUrl}
/>
Expand Down
Loading
Loading