i18n 적용
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import type { ChangeEvent } from "react";
|
||||
import { useState } from "react";
|
||||
import { useAppLocale } from "@/features/i18n/LocaleProvider";
|
||||
import { getEditorColorPickerFieldMessages } from "@/features/i18n/messages/editorColorPickerField";
|
||||
|
||||
export type ColorPaletteItem = {
|
||||
// 팔레트 식별자
|
||||
@@ -75,6 +77,9 @@ export function ColorPickerField({
|
||||
}: ColorPickerFieldProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const locale = useAppLocale();
|
||||
const m = getEditorColorPickerFieldMessages(locale);
|
||||
|
||||
const colorInputValue = value && value.startsWith("#") ? value : "#ffffff";
|
||||
// 컬러 인풋 변경 시 HEX 문자열을 onChange로 전달한다.
|
||||
const handleColorInputChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
@@ -122,7 +127,7 @@ export function ColorPickerField({
|
||||
<input
|
||||
className="w-28 flex-none rounded border border-slate-300 bg-white px-2 py-1 text-xs text-slate-900 outline-none focus:border-sky-500 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100"
|
||||
aria-label={ariaLabelHexInput}
|
||||
placeholder="예: #ff0000"
|
||||
placeholder={m.hexPlaceholder}
|
||||
value={value}
|
||||
onChange={handleHexInputChange}
|
||||
/>
|
||||
@@ -139,7 +144,9 @@ export function ColorPickerField({
|
||||
style={{ backgroundColor: selectedPalette?.color ?? value ?? "#ffffff" }}
|
||||
/>
|
||||
<span className="truncate text-slate-700 dark:text-slate-100">
|
||||
{selectedPalette?.label ?? "색상 팔레트"}
|
||||
{selectedPalette
|
||||
? m.paletteLabels[selectedPalette.id] ?? selectedPalette.label
|
||||
: m.dropdownLabelDefault}
|
||||
</span>
|
||||
</span>
|
||||
<span className="text-slate-400 dark:text-slate-500 text-[10px]">▼</span>
|
||||
@@ -166,7 +173,7 @@ export function ColorPickerField({
|
||||
className="inline-block h-3 w-3 rounded-full border border-slate-300 dark:border-slate-700"
|
||||
style={{ backgroundColor: item.color }}
|
||||
/>
|
||||
<span>{item.label}</span>
|
||||
<span>{m.paletteLabels[item.id] ?? item.label}</span>
|
||||
</span>
|
||||
</button>
|
||||
))}
|
||||
|
||||
@@ -39,6 +39,8 @@ import {
|
||||
computeFormRadioPublicTokens,
|
||||
computeFormControllerPublicTokens,
|
||||
} from "@/features/editor/utils/formHelpers";
|
||||
import { useAppLocale } from "@/features/i18n/LocaleProvider";
|
||||
import { getPublicPageRendererMessages } from "@/features/i18n/messages/publicPageRenderer";
|
||||
|
||||
// 섹션 레이아웃/스타일 토큰을 실제 Tailwind 클래스 조합으로 변환하는 유틸
|
||||
// (에디터/퍼블릭 렌더러에서 동일한 규칙을 재사용하기 위해 export 한다.)
|
||||
@@ -101,6 +103,8 @@ const convertPxStringToEm = (value?: string | null) => {
|
||||
};
|
||||
|
||||
export function PublicPageRenderer({ blocks, projectSlug }: PublicPageRendererProps) {
|
||||
const locale = useAppLocale();
|
||||
const m = getPublicPageRendererMessages(locale);
|
||||
const [formStatus, setFormStatus] = useState<"idle" | "submitting" | "success" | "error">("idle");
|
||||
const [formMessage, setFormMessage] = useState<string>("");
|
||||
|
||||
@@ -186,7 +190,7 @@ export function PublicPageRenderer({ blocks, projectSlug }: PublicPageRendererPr
|
||||
setFormStatus("error");
|
||||
|
||||
const bulletLines = missingRequiredLabels.map((label) => `- ${label}`).join("\n");
|
||||
const message = `다음 필수 항목을 입력해 주세요:\n${bulletLines}`;
|
||||
const message = `${m.requiredFieldsPrefix}\n${bulletLines}`;
|
||||
|
||||
setFormMessage(message);
|
||||
return;
|
||||
@@ -257,15 +261,15 @@ export function PublicPageRenderer({ blocks, projectSlug }: PublicPageRendererPr
|
||||
|
||||
if (res.ok) {
|
||||
setFormStatus("success");
|
||||
setFormMessage(props.successMessage ?? "성공적으로 전송되었습니다.");
|
||||
setFormMessage(props.successMessage ?? m.submitSuccessDefault);
|
||||
} else {
|
||||
setFormStatus("error");
|
||||
setFormMessage(props.errorMessage ?? "전송 중 오류가 발생했습니다.");
|
||||
setFormMessage(props.errorMessage ?? m.submitErrorDefault);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[PublicPageRenderer] form submit error", error);
|
||||
setFormStatus("error");
|
||||
setFormMessage(props.errorMessage ?? "전송 중 오류가 발생했습니다.");
|
||||
setFormMessage(props.errorMessage ?? m.submitErrorDefault);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -541,7 +545,7 @@ export function PublicPageRenderer({ blocks, projectSlug }: PublicPageRendererPr
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
src={props.groupLabelImageUrl}
|
||||
alt={props.groupLabel || "폼 그룹 타이틀"}
|
||||
alt={props.groupLabel || m.checkboxGroupLabelImageAltFallback}
|
||||
className="inline-block max-w-full h-auto"
|
||||
style={tokens.groupTextStyle}
|
||||
/>
|
||||
@@ -571,7 +575,7 @@ export function PublicPageRenderer({ blocks, projectSlug }: PublicPageRendererPr
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
src={opt.labelImageUrl}
|
||||
alt={opt.label || props.groupLabel || "체크박스 옵션"}
|
||||
alt={opt.label || props.groupLabel || m.checkboxOptionImageAltFallback}
|
||||
className="inline-block max-w-full h-auto"
|
||||
style={tokens.optionTextStyle}
|
||||
/>
|
||||
@@ -634,7 +638,7 @@ export function PublicPageRenderer({ blocks, projectSlug }: PublicPageRendererPr
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
src={props.groupLabelImageUrl}
|
||||
alt={props.groupLabel || "폼 그룹 타이틀"}
|
||||
alt={props.groupLabel || m.checkboxGroupLabelImageAltFallback}
|
||||
className="inline-block max-w-full h-auto"
|
||||
style={tokens.groupTextStyle}
|
||||
/>
|
||||
@@ -663,7 +667,7 @@ export function PublicPageRenderer({ blocks, projectSlug }: PublicPageRendererPr
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
src={opt.labelImageUrl}
|
||||
alt={opt.label || props.groupLabel || "라디오 옵션"}
|
||||
alt={opt.label || props.groupLabel || m.radioOptionImageAltFallback}
|
||||
className="inline-block max-w-full h-auto"
|
||||
style={tokens.optionTextStyle}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import { createContext, useContext, useState } from "react";
|
||||
import type { AppLocale } from "./locale";
|
||||
import { DEFAULT_LOCALE } from "./locale";
|
||||
|
||||
type LocaleContextValue = {
|
||||
locale: AppLocale;
|
||||
setLocale: (locale: AppLocale) => void;
|
||||
};
|
||||
|
||||
const LocaleContext = createContext<LocaleContextValue>({
|
||||
locale: DEFAULT_LOCALE,
|
||||
setLocale: () => {
|
||||
// no-op default
|
||||
},
|
||||
});
|
||||
|
||||
export function LocaleProvider({
|
||||
initialLocale,
|
||||
children,
|
||||
}: {
|
||||
initialLocale: AppLocale;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
const [locale, setLocale] = useState<AppLocale>(initialLocale);
|
||||
|
||||
return <LocaleContext.Provider value={{ locale, setLocale }}>{children}</LocaleContext.Provider>;
|
||||
}
|
||||
|
||||
export function useAppLocale(): AppLocale {
|
||||
return useContext(LocaleContext).locale;
|
||||
}
|
||||
|
||||
export function useLocaleActions() {
|
||||
const { setLocale } = useContext(LocaleContext);
|
||||
return { setLocale };
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
"use client";
|
||||
|
||||
import { useAppLocale, useLocaleActions } from "./LocaleProvider";
|
||||
import type { AppLocale } from "./locale";
|
||||
|
||||
export function LocaleSwitcher() {
|
||||
const locale = useAppLocale();
|
||||
const { setLocale } = useLocaleActions();
|
||||
|
||||
const handleChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const nextLocale = event.target.value as AppLocale;
|
||||
setLocale(nextLocale);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed bottom-4 right-4 z-50 text-xs">
|
||||
<label className="inline-flex items-center gap-1 rounded border border-slate-300 bg-white/80 px-2 py-1 text-slate-700 shadow-sm backdrop-blur dark:border-slate-700 dark:bg-slate-900/80 dark:text-slate-100">
|
||||
<span>Language</span>
|
||||
<select
|
||||
className="bg-transparent text-xs outline-none"
|
||||
value={locale}
|
||||
onChange={handleChange}
|
||||
>
|
||||
<option value="en">English</option>
|
||||
<option value="ko">한국어</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
export const SUPPORTED_LOCALES = ["en", "ko"] as const;
|
||||
export type AppLocale = (typeof SUPPORTED_LOCALES)[number];
|
||||
|
||||
// 기본 로케일은 항상 en
|
||||
export const DEFAULT_LOCALE: AppLocale = "en";
|
||||
|
||||
// Accept-Language 헤더 문자열에서 앱 로케일(en/ko)을 결정한다.
|
||||
// - ko 가 포함되어 있으면 ko
|
||||
// - 그렇지 않으면 기본(en)
|
||||
export function resolveLocaleFromAcceptLanguage(header: string | null | undefined): AppLocale {
|
||||
if (!header) {
|
||||
return DEFAULT_LOCALE;
|
||||
}
|
||||
|
||||
const value = header.toLowerCase();
|
||||
|
||||
if (value.includes("ko")) {
|
||||
return "ko";
|
||||
}
|
||||
|
||||
return DEFAULT_LOCALE;
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type LoginMessages = {
|
||||
title: string;
|
||||
description: string;
|
||||
emailLabel: string;
|
||||
passwordLabel: string;
|
||||
submitIdle: string;
|
||||
submitLoading: string;
|
||||
themeToggleLabel: string;
|
||||
errorLoginFailed: string;
|
||||
errorNetwork: string;
|
||||
signupPromptPrefix: string;
|
||||
signupLinkText: string;
|
||||
signupPromptSuffix: string;
|
||||
};
|
||||
|
||||
export type SignupMessages = {
|
||||
title: string;
|
||||
description: string;
|
||||
emailLabel: string;
|
||||
passwordLabel: string;
|
||||
passwordConfirmLabel: string;
|
||||
submitIdle: string;
|
||||
submitLoading: string;
|
||||
mismatchError: string;
|
||||
signupFailedFallbackError: string;
|
||||
errorNetwork: string;
|
||||
passwordStrengthPrefix: string;
|
||||
passwordStrengthWeak: string;
|
||||
passwordStrengthMedium: string;
|
||||
passwordStrengthStrong: string;
|
||||
loginPromptPrefix: string;
|
||||
loginLinkText: string;
|
||||
loginPromptSuffix: string;
|
||||
};
|
||||
|
||||
export type AuthMessages = {
|
||||
login: LoginMessages;
|
||||
signup: SignupMessages;
|
||||
};
|
||||
|
||||
const AUTH_MESSAGES: Record<AppLocale, AuthMessages> = {
|
||||
en: {
|
||||
login: {
|
||||
title: "Log in",
|
||||
description: "Sign in to manage and save your projects.",
|
||||
emailLabel: "Email",
|
||||
passwordLabel: "Password",
|
||||
submitIdle: "Log in",
|
||||
submitLoading: "Logging in...",
|
||||
themeToggleLabel: "Toggle theme",
|
||||
errorLoginFailed: "Failed to log in. Please try again.",
|
||||
errorNetwork: "A network error occurred. Please try again later.",
|
||||
signupPromptPrefix: "Don't have an account yet?",
|
||||
signupLinkText: "Sign up",
|
||||
signupPromptSuffix: "",
|
||||
},
|
||||
signup: {
|
||||
title: "Sign up",
|
||||
description: "Create a new account to save and manage your projects.",
|
||||
emailLabel: "Email",
|
||||
passwordLabel: "Password",
|
||||
passwordConfirmLabel: "Confirm password",
|
||||
submitIdle: "Sign up",
|
||||
submitLoading: "Signing up...",
|
||||
mismatchError: "Password and confirmation do not match.",
|
||||
signupFailedFallbackError: "Failed to sign up. Please try again.",
|
||||
errorNetwork: "A network error occurred. Please try again later.",
|
||||
passwordStrengthPrefix: "Password strength:",
|
||||
passwordStrengthWeak: "Weak",
|
||||
passwordStrengthMedium: "Medium",
|
||||
passwordStrengthStrong: "Strong",
|
||||
loginPromptPrefix: "Already have an account?",
|
||||
loginLinkText: "Log in",
|
||||
loginPromptSuffix: "",
|
||||
},
|
||||
},
|
||||
ko: {
|
||||
login: {
|
||||
title: "로그인",
|
||||
description: "프로젝트를 관리하려면 먼저 계정으로 로그인하세요.",
|
||||
emailLabel: "이메일",
|
||||
passwordLabel: "비밀번호",
|
||||
submitIdle: "로그인",
|
||||
submitLoading: "로그인 중...",
|
||||
themeToggleLabel: "테마 전환",
|
||||
errorLoginFailed: "로그인에 실패했습니다. 다시 시도해 주세요.",
|
||||
errorNetwork: "네트워크 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.",
|
||||
signupPromptPrefix: "아직 계정이 없다면",
|
||||
signupLinkText: "회원가입",
|
||||
signupPromptSuffix: "을 진행해 주세요.",
|
||||
},
|
||||
signup: {
|
||||
title: "회원가입",
|
||||
description: "새 계정을 생성한 뒤 프로젝트를 저장하고 관리할 수 있습니다.",
|
||||
emailLabel: "이메일",
|
||||
passwordLabel: "비밀번호",
|
||||
passwordConfirmLabel: "비밀번호 확인",
|
||||
submitIdle: "회원가입",
|
||||
submitLoading: "회원가입 중...",
|
||||
mismatchError: "비밀번호와 비밀번호 확인이 일치하지 않습니다.",
|
||||
signupFailedFallbackError: "회원가입에 실패했습니다. 다시 시도해 주세요.",
|
||||
errorNetwork: "네트워크 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.",
|
||||
passwordStrengthPrefix: "비밀번호 난이도:",
|
||||
passwordStrengthWeak: "약함",
|
||||
passwordStrengthMedium: "보통",
|
||||
passwordStrengthStrong: "강함",
|
||||
loginPromptPrefix: "이미 계정이 있다면",
|
||||
loginLinkText: "로그인",
|
||||
loginPromptSuffix: "으로 이동해 주세요.",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export function getAuthMessages(locale: AppLocale | null | undefined): AuthMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return AUTH_MESSAGES[key] ?? AUTH_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
// 대시보드/프로젝트 목록/전체 제출 내역 상단 GNB 및 헤더용 i18n 메시지
|
||||
// - 로그인/회원가입과 동일하게 en(기본), ko 를 지원한다.
|
||||
|
||||
export type DashboardMessages = {
|
||||
// 메인 대시보드 헤더 제목/설명
|
||||
title: string;
|
||||
description: string;
|
||||
// 상단 GNB 탭 레이블
|
||||
navDashboard: string;
|
||||
navProjects: string;
|
||||
navSubmissions: string;
|
||||
// 헤더 오른쪽 액션 버튼/메뉴
|
||||
themeToggleLabel: string;
|
||||
menuLabel: string;
|
||||
logoutLabel: string;
|
||||
summaryTotalProjectsLabel: string;
|
||||
summaryTotalSubmissionsLabel: string;
|
||||
summaryTodaySubmissionsLabel: string;
|
||||
summaryLast7DaysSubmissionsLabel: string;
|
||||
chartTitle: string;
|
||||
chartSubtitle: string;
|
||||
chartEmptyLabel: string;
|
||||
sectionProjectsTitle: string;
|
||||
sectionProjectsEmpty: string;
|
||||
projectTotalSubmissionsPrefix: string;
|
||||
projectTotalSubmissionsSuffix: string;
|
||||
projectLatestSubmissionPrefix: string;
|
||||
projectLatestSubmissionEmpty: string;
|
||||
projectViewSubmissionsLink: string;
|
||||
projectOpenPublicPageLink: string;
|
||||
errorUnauthorized: string;
|
||||
errorGeneric: string;
|
||||
loadingText: string;
|
||||
};
|
||||
|
||||
const DASHBOARD_MESSAGES: Record<AppLocale, DashboardMessages> = {
|
||||
en: {
|
||||
title: "Dashboard",
|
||||
description: "A quick overview of your projects and form submissions.",
|
||||
navDashboard: "Dashboard",
|
||||
navProjects: "Projects",
|
||||
navSubmissions: "All submissions",
|
||||
themeToggleLabel: "Toggle theme",
|
||||
menuLabel: "Menu",
|
||||
logoutLabel: "Log out",
|
||||
summaryTotalProjectsLabel: "Projects",
|
||||
summaryTotalSubmissionsLabel: "Total form submissions",
|
||||
summaryTodaySubmissionsLabel: "Submissions today",
|
||||
summaryLast7DaysSubmissionsLabel: "Submissions in last 7 days",
|
||||
chartTitle: "Recent submissions (daily)",
|
||||
chartSubtitle: "Only dates with recent activity are shown.",
|
||||
chartEmptyLabel: "No daily submission data yet.",
|
||||
sectionProjectsTitle: "Submissions by project",
|
||||
sectionProjectsEmpty: "No projects created yet or no submissions have been received.",
|
||||
projectTotalSubmissionsPrefix: "Total ",
|
||||
projectTotalSubmissionsSuffix: " submissions",
|
||||
projectLatestSubmissionPrefix: "Last submission:",
|
||||
projectLatestSubmissionEmpty: "No submissions yet",
|
||||
projectViewSubmissionsLink: "View form submissions",
|
||||
projectOpenPublicPageLink: "Open public page",
|
||||
errorUnauthorized: "You need to be signed in to view the dashboard. Please log in again.",
|
||||
errorGeneric: "An error occurred while loading the dashboard. Please try again later.",
|
||||
loadingText: "Loading dashboard data...",
|
||||
},
|
||||
ko: {
|
||||
title: "대시보드",
|
||||
description: "프로젝트와 폼 제출 현황을 한눈에 확인할 수 있는 요약 화면입니다.",
|
||||
navDashboard: "대시보드",
|
||||
navProjects: "프로젝트 목록",
|
||||
navSubmissions: "전체 제출 내역",
|
||||
themeToggleLabel: "테마 전환",
|
||||
menuLabel: "메뉴",
|
||||
logoutLabel: "로그아웃",
|
||||
summaryTotalProjectsLabel: "프로젝트 수",
|
||||
summaryTotalSubmissionsLabel: "전체 폼 제출 수",
|
||||
summaryTodaySubmissionsLabel: "오늘 제출 수",
|
||||
summaryLast7DaysSubmissionsLabel: "최근 7일 제출 수",
|
||||
chartTitle: "최근 제출 추이 (일별)",
|
||||
chartSubtitle: "최근 활동이 있는 날짜만 표시됩니다.",
|
||||
chartEmptyLabel: "아직 일별 제출 내역이 없습니다.",
|
||||
sectionProjectsTitle: "프로젝트별 제출 현황",
|
||||
sectionProjectsEmpty: "아직 생성된 프로젝트가 없거나 제출 내역이 없습니다.",
|
||||
projectTotalSubmissionsPrefix: "총 제출 ",
|
||||
projectTotalSubmissionsSuffix: "건",
|
||||
projectLatestSubmissionPrefix: "최근 제출:",
|
||||
projectLatestSubmissionEmpty: "제출 내역 없음",
|
||||
projectViewSubmissionsLink: "폼 제출 내역 보기",
|
||||
projectOpenPublicPageLink: "퍼블릭 페이지 열기",
|
||||
errorUnauthorized:
|
||||
"대시보드를 보려면 로그인이 필요합니다. 다시 로그인해 주세요.",
|
||||
errorGeneric:
|
||||
"대시보드 데이터를 불러오는 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.",
|
||||
loadingText: "대시보드 데이터를 불러오는 중입니다...",
|
||||
},
|
||||
};
|
||||
|
||||
export function getDashboardMessages(locale: AppLocale | null | undefined): DashboardMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return DASHBOARD_MESSAGES[key] ?? DASHBOARD_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorMessages = {
|
||||
headerTitle: string;
|
||||
headerDescription: string;
|
||||
navProjects: string;
|
||||
navPreview: string;
|
||||
undoLabel: string;
|
||||
redoLabel: string;
|
||||
menuLabel: string;
|
||||
menuProjectSaveLoad: string;
|
||||
menuJsonImportExport: string;
|
||||
menuExportZip: string;
|
||||
menuClearCanvas: string;
|
||||
menuDeleteProject: string;
|
||||
confirmClearCanvas: string;
|
||||
confirmDeleteProject: string;
|
||||
modalProjectTitle: string;
|
||||
modalProjectTitleLabel: string;
|
||||
modalProjectSlugLabel: string;
|
||||
modalSaveButton: string;
|
||||
modalLoadButton: string;
|
||||
projectMessageSlugRequired: string;
|
||||
projectMessageSaveFailed: string;
|
||||
projectMessageSaveError: string;
|
||||
projectMessageSaveSuccessPrefix: string;
|
||||
projectMessageLoadSlugRequired: string;
|
||||
projectMessageLoadFailed: string;
|
||||
projectMessageLoadLocalSuccessPrefix: string;
|
||||
projectMessageLoadServerSuccessPrefix: string;
|
||||
projectMessageInvalidFormat: string;
|
||||
projectMessageLoadError: string;
|
||||
projectMessageDeleteSlugMissing: string;
|
||||
projectMessageDeleteFailed: string;
|
||||
projectMessageDeleteSuccess: string;
|
||||
projectMessageDeleteError: string;
|
||||
jsonModalTitle: string;
|
||||
jsonModalSubtitle: string;
|
||||
jsonExportButton: string;
|
||||
jsonClearCanvasButton: string;
|
||||
jsonEditorStateLabel: string;
|
||||
jsonImportLabel: string;
|
||||
jsonApplyButton: string;
|
||||
listItemToolbarMoveUpLabel: string;
|
||||
listItemToolbarMoveDownLabel: string;
|
||||
listItemToolbarIndentLabel: string;
|
||||
listItemToolbarOutdentLabel: string;
|
||||
};
|
||||
|
||||
const EDITOR_MESSAGES: Record<AppLocale, EditorMessages> = {
|
||||
en: {
|
||||
headerTitle: "Page Editor",
|
||||
headerDescription: "Build and edit your landing pages with a visual editor.",
|
||||
navProjects: "Projects",
|
||||
navPreview: "Open preview",
|
||||
undoLabel: "Undo",
|
||||
redoLabel: "Redo",
|
||||
menuLabel: "Menu",
|
||||
menuProjectSaveLoad: "Save / load project",
|
||||
menuJsonImportExport: "JSON export / import",
|
||||
menuExportZip: "Export as page files (ZIP)",
|
||||
menuClearCanvas: "Clear canvas",
|
||||
menuDeleteProject: "Delete project",
|
||||
confirmClearCanvas:
|
||||
"Clear all blocks on the canvas? This can only be undone with the undo history.",
|
||||
confirmDeleteProject:
|
||||
"Delete the current project? This cannot be undone. Local and autosave data will also be removed.",
|
||||
modalProjectTitle: "Save / load project",
|
||||
modalProjectTitleLabel: "Project title",
|
||||
modalProjectSlugLabel: "Project address (e.g. my-landing)",
|
||||
modalSaveButton: "Save (local + server)",
|
||||
modalLoadButton: "Load",
|
||||
projectMessageSlugRequired: "Please enter a project address.",
|
||||
projectMessageSaveFailed: "Failed to save the project.",
|
||||
projectMessageSaveError: "An error occurred while saving the project.",
|
||||
projectMessageSaveSuccessPrefix: "Project saved: ",
|
||||
projectMessageLoadSlugRequired: "Please enter an address to load.",
|
||||
projectMessageLoadFailed: "Failed to load the project.",
|
||||
projectMessageLoadLocalSuccessPrefix: "Loaded project from local: ",
|
||||
projectMessageLoadServerSuccessPrefix: "Loaded project from server: ",
|
||||
projectMessageInvalidFormat: "Project data format is invalid.",
|
||||
projectMessageLoadError: "An error occurred while loading the project.",
|
||||
projectMessageDeleteSlugMissing: "There is no project address to delete.",
|
||||
projectMessageDeleteFailed: "Failed to delete the project.",
|
||||
projectMessageDeleteSuccess: "Project deleted.",
|
||||
projectMessageDeleteError: "An error occurred while deleting the project.",
|
||||
jsonModalTitle: "JSON Export / Import",
|
||||
jsonModalSubtitle: "* Import or export the current editor state as JSON.",
|
||||
jsonExportButton: "Export JSON",
|
||||
jsonClearCanvasButton: "Clear canvas",
|
||||
jsonEditorStateLabel: "Editor state JSON",
|
||||
jsonImportLabel: "Import from JSON",
|
||||
jsonApplyButton: "Apply JSON",
|
||||
listItemToolbarMoveUpLabel: "Move item up",
|
||||
listItemToolbarMoveDownLabel: "Move item down",
|
||||
listItemToolbarIndentLabel: "Indent item",
|
||||
listItemToolbarOutdentLabel: "Outdent item",
|
||||
},
|
||||
ko: {
|
||||
headerTitle: "페이지 에디터",
|
||||
headerDescription: "랜딩 페이지를 시각적으로 구성할 수 있는 에디터입니다.",
|
||||
navProjects: "프로젝트 목록",
|
||||
navPreview: "프리뷰 열기",
|
||||
undoLabel: "실행 취소",
|
||||
redoLabel: "다시 실행",
|
||||
menuLabel: "메뉴",
|
||||
menuProjectSaveLoad: "프로젝트 저장/불러오기",
|
||||
menuJsonImportExport: "JSON 내보내기/불러오기",
|
||||
menuExportZip: "페이지 파일로 내보내기 (ZIP)",
|
||||
menuClearCanvas: "캔버스 초기화",
|
||||
menuDeleteProject: "프로젝트 삭제",
|
||||
confirmClearCanvas:
|
||||
"캔버스를 모두 초기화할까요? 이 작업은 실행 취소 히스토리로만 되돌릴 수 있습니다.",
|
||||
confirmDeleteProject:
|
||||
"현재 프로젝트를 삭제할까요? 삭제 후에는 되돌릴 수 없습니다. (로컬 저장 및 자동저장 데이터도 함께 삭제됩니다.)",
|
||||
modalProjectTitle: "프로젝트 저장 / 불러오기",
|
||||
modalProjectTitleLabel: "프로젝트 제목",
|
||||
modalProjectSlugLabel: "프로젝트 주소 (예: my-landing)",
|
||||
modalSaveButton: "저장 (로컬 + 서버)",
|
||||
modalLoadButton: "불러오기",
|
||||
projectMessageSlugRequired: "프로젝트 주소를 입력해 주세요.",
|
||||
projectMessageSaveFailed: "프로젝트 저장에 실패했습니다.",
|
||||
projectMessageSaveError: "프로젝트 저장 중 오류가 발생했습니다.",
|
||||
projectMessageSaveSuccessPrefix: "프로젝트가 저장되었습니다: ",
|
||||
projectMessageLoadSlugRequired: "불러올 주소를 입력해 주세요.",
|
||||
projectMessageLoadFailed: "프로젝트를 불러오지 못했습니다.",
|
||||
projectMessageLoadLocalSuccessPrefix: "로컬에서 프로젝트를 불러왔습니다: ",
|
||||
projectMessageLoadServerSuccessPrefix: "프로젝트를 불러왔습니다: ",
|
||||
projectMessageInvalidFormat: "프로젝트 데이터 형식이 올바르지 않습니다.",
|
||||
projectMessageLoadError: "프로젝트 불러오기 중 오류가 발생했습니다.",
|
||||
projectMessageDeleteSlugMissing: "삭제할 프로젝트 주소가 없습니다.",
|
||||
projectMessageDeleteFailed: "프로젝트 삭제에 실패했습니다.",
|
||||
projectMessageDeleteSuccess: "프로젝트가 삭제되었습니다.",
|
||||
projectMessageDeleteError: "프로젝트 삭제 중 오류가 발생했습니다.",
|
||||
jsonModalTitle: "JSON Export / Import",
|
||||
jsonModalSubtitle: "* 에디터 내용을 가져오거나 내보낼 수 있습니다.",
|
||||
jsonExportButton: "JSON 내보내기",
|
||||
jsonClearCanvasButton: "캔버스 초기화",
|
||||
jsonEditorStateLabel: "에디터 상태 JSON",
|
||||
jsonImportLabel: "JSON에서 불러오기",
|
||||
jsonApplyButton: "JSON 적용하기",
|
||||
listItemToolbarMoveUpLabel: "아이템 위로 이동",
|
||||
listItemToolbarMoveDownLabel: "아이템 아래로 이동",
|
||||
listItemToolbarIndentLabel: "아이템 들여쓰기",
|
||||
listItemToolbarOutdentLabel: "아이템 내어쓰기",
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorMessages(locale: AppLocale | null | undefined): EditorMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_MESSAGES[key] ?? EDITOR_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorButtonPanelMessages = {
|
||||
buttonTextLabel: string;
|
||||
buttonTextAria: string;
|
||||
|
||||
imageSectionTitle: string;
|
||||
imageSourceLabel: string;
|
||||
imageSourceAria: string;
|
||||
imageSourceOptionNone: string;
|
||||
imageSourceOptionUrl: string;
|
||||
imageSourceOptionUpload: string;
|
||||
|
||||
imageUrlLabel: string;
|
||||
imageUrlAria: string;
|
||||
imageUploadLabel: string;
|
||||
imageUploadAria: string;
|
||||
|
||||
imageAltLabel: string;
|
||||
imageAltAria: string;
|
||||
|
||||
imagePlacementLabel: string;
|
||||
imagePlacementAria: string;
|
||||
imagePlacementOptionLeft: string;
|
||||
imagePlacementOptionRight: string;
|
||||
imagePlacementOptionTop: string;
|
||||
imagePlacementOptionBottom: string;
|
||||
|
||||
paddingXLabel: string;
|
||||
paddingYLabel: string;
|
||||
|
||||
linkLabel: string;
|
||||
linkAria: string;
|
||||
|
||||
alignLabel: string;
|
||||
alignAria: string;
|
||||
alignOptionLeft: string;
|
||||
alignOptionCenter: string;
|
||||
alignOptionRight: string;
|
||||
|
||||
textColorLabel: string;
|
||||
textColorPickerAria: string;
|
||||
textColorHexAria: string;
|
||||
|
||||
styleLabel: string;
|
||||
styleAria: string;
|
||||
styleOptionSolid: string;
|
||||
styleOptionOutline: string;
|
||||
styleOptionGhost: string;
|
||||
|
||||
fillColorLabel: string;
|
||||
fillColorPickerAria: string;
|
||||
fillColorHexAria: string;
|
||||
|
||||
strokeColorLabel: string;
|
||||
strokeColorPickerAria: string;
|
||||
strokeColorHexAria: string;
|
||||
|
||||
borderRadiusLabel: string;
|
||||
borderRadiusPresetNone: string;
|
||||
borderRadiusPresetSmall: string;
|
||||
borderRadiusPresetMedium: string;
|
||||
borderRadiusPresetLarge: string;
|
||||
borderRadiusPresetFull: string;
|
||||
|
||||
widthModeLabel: string;
|
||||
widthModeAria: string;
|
||||
widthModeOptionAuto: string;
|
||||
widthModeOptionFull: string;
|
||||
widthModeOptionFixed: string;
|
||||
|
||||
fixedWidthLabel: string;
|
||||
fixedWidthUnitLabel: string;
|
||||
fixedWidthPresetSmall: string;
|
||||
fixedWidthPresetMedium: string;
|
||||
fixedWidthPresetLarge: string;
|
||||
|
||||
fontSizeLabel: string;
|
||||
fontSizeUnitLabel: string;
|
||||
|
||||
lineHeightLabel: string;
|
||||
lineHeightPresetTight: string;
|
||||
lineHeightPresetNormal: string;
|
||||
lineHeightPresetRelaxed: string;
|
||||
|
||||
letterSpacingLabel: string;
|
||||
letterSpacingUnitLabel: string;
|
||||
letterSpacingPresetTighter: string;
|
||||
letterSpacingPresetTight: string;
|
||||
letterSpacingPresetNormal: string;
|
||||
letterSpacingPresetWide: string;
|
||||
letterSpacingPresetWider: string;
|
||||
};
|
||||
|
||||
const EDITOR_BUTTON_PANEL_MESSAGES: Record<AppLocale, EditorButtonPanelMessages> = {
|
||||
en: {
|
||||
buttonTextLabel: "Button text",
|
||||
buttonTextAria: "Button text",
|
||||
|
||||
imageSectionTitle: "Button image",
|
||||
imageSourceLabel: "Button image source",
|
||||
imageSourceAria: "Button image source",
|
||||
imageSourceOptionNone: "None",
|
||||
imageSourceOptionUrl: "URL",
|
||||
imageSourceOptionUpload: "File upload",
|
||||
|
||||
imageUrlLabel: "Button image URL",
|
||||
imageUrlAria: "Button image URL",
|
||||
imageUploadLabel: "Button image file upload",
|
||||
imageUploadAria: "Button image file upload",
|
||||
|
||||
imageAltLabel: "Button image alt text",
|
||||
imageAltAria: "Button image alt text",
|
||||
|
||||
imagePlacementLabel: "Button image placement",
|
||||
imagePlacementAria: "Button image placement",
|
||||
imagePlacementOptionLeft: "Text left",
|
||||
imagePlacementOptionRight: "Text right",
|
||||
imagePlacementOptionTop: "Text top",
|
||||
imagePlacementOptionBottom: "Text bottom",
|
||||
|
||||
paddingXLabel: "Horizontal padding (px)",
|
||||
paddingYLabel: "Vertical padding (px)",
|
||||
|
||||
linkLabel: "Button link",
|
||||
linkAria: "Button link",
|
||||
|
||||
alignLabel: "Alignment",
|
||||
alignAria: "Button alignment",
|
||||
alignOptionLeft: "Left",
|
||||
alignOptionCenter: "Center",
|
||||
alignOptionRight: "Right",
|
||||
|
||||
textColorLabel: "Text color",
|
||||
textColorPickerAria: "Button text color picker",
|
||||
textColorHexAria: "Button text color HEX",
|
||||
|
||||
styleLabel: "Style",
|
||||
styleAria: "Button style",
|
||||
styleOptionSolid: "Fill",
|
||||
styleOptionOutline: "Outline",
|
||||
styleOptionGhost: "Ghost",
|
||||
|
||||
fillColorLabel: "Fill color",
|
||||
fillColorPickerAria: "Button fill color picker",
|
||||
fillColorHexAria: "Button fill color HEX",
|
||||
|
||||
strokeColorLabel: "Border color",
|
||||
strokeColorPickerAria: "Button border color picker",
|
||||
strokeColorHexAria: "Button border color HEX",
|
||||
|
||||
borderRadiusLabel: "Border radius",
|
||||
borderRadiusPresetNone: "None",
|
||||
borderRadiusPresetSmall: "Small",
|
||||
borderRadiusPresetMedium: "Medium",
|
||||
borderRadiusPresetLarge: "Large",
|
||||
borderRadiusPresetFull: "Full",
|
||||
|
||||
widthModeLabel: "Button width mode",
|
||||
widthModeAria: "Button width mode",
|
||||
widthModeOptionAuto: "Auto",
|
||||
widthModeOptionFull: "Full width",
|
||||
widthModeOptionFixed: "Fixed",
|
||||
|
||||
fixedWidthLabel: "Button fixed width",
|
||||
fixedWidthUnitLabel: "(px)",
|
||||
fixedWidthPresetSmall: "Small",
|
||||
fixedWidthPresetMedium: "Medium",
|
||||
fixedWidthPresetLarge: "Wide",
|
||||
|
||||
fontSizeLabel: "Button font size",
|
||||
fontSizeUnitLabel: "(px)",
|
||||
|
||||
lineHeightLabel: "Line height",
|
||||
lineHeightPresetTight: "Tight",
|
||||
lineHeightPresetNormal: "Normal",
|
||||
lineHeightPresetRelaxed: "Relaxed",
|
||||
|
||||
letterSpacingLabel: "Letter spacing",
|
||||
letterSpacingUnitLabel: "(px)",
|
||||
letterSpacingPresetTighter: "Very tight",
|
||||
letterSpacingPresetTight: "Tight",
|
||||
letterSpacingPresetNormal: "Normal",
|
||||
letterSpacingPresetWide: "Wide",
|
||||
letterSpacingPresetWider: "Very wide",
|
||||
},
|
||||
ko: {
|
||||
buttonTextLabel: "버튼 텍스트",
|
||||
buttonTextAria: "버튼 텍스트",
|
||||
|
||||
imageSectionTitle: "버튼 이미지",
|
||||
imageSourceLabel: "버튼 이미지 소스",
|
||||
imageSourceAria: "버튼 이미지 소스",
|
||||
imageSourceOptionNone: "사용 안 함",
|
||||
imageSourceOptionUrl: "URL",
|
||||
imageSourceOptionUpload: "파일 업로드",
|
||||
|
||||
imageUrlLabel: "버튼 이미지 URL",
|
||||
imageUrlAria: "버튼 이미지 URL",
|
||||
imageUploadLabel: "버튼 이미지 파일 업로드",
|
||||
imageUploadAria: "버튼 이미지 파일 업로드",
|
||||
|
||||
imageAltLabel: "버튼 이미지 대체 텍스트",
|
||||
imageAltAria: "버튼 이미지 대체 텍스트",
|
||||
|
||||
imagePlacementLabel: "버튼 이미지 위치",
|
||||
imagePlacementAria: "버튼 이미지 위치",
|
||||
imagePlacementOptionLeft: "텍스트 왼쪽",
|
||||
imagePlacementOptionRight: "텍스트 오른쪽",
|
||||
imagePlacementOptionTop: "텍스트 위쪽",
|
||||
imagePlacementOptionBottom: "텍스트 아래쪽",
|
||||
|
||||
paddingXLabel: "가로 패딩 (px)",
|
||||
paddingYLabel: "세로 패딩 (px)",
|
||||
|
||||
linkLabel: "버튼 링크",
|
||||
linkAria: "버튼 링크",
|
||||
|
||||
alignLabel: "정렬",
|
||||
alignAria: "버튼 정렬",
|
||||
alignOptionLeft: "왼쪽",
|
||||
alignOptionCenter: "가운데",
|
||||
alignOptionRight: "오른쪽",
|
||||
|
||||
textColorLabel: "텍스트 색상",
|
||||
textColorPickerAria: "버튼 텍스트 색상 피커",
|
||||
textColorHexAria: "버튼 텍스트 색상 HEX",
|
||||
|
||||
styleLabel: "스타일",
|
||||
styleAria: "버튼 스타일",
|
||||
styleOptionSolid: "채움",
|
||||
styleOptionOutline: "외곽선",
|
||||
styleOptionGhost: "고스트",
|
||||
|
||||
fillColorLabel: "채움 색상",
|
||||
fillColorPickerAria: "버튼 채움 색상 피커",
|
||||
fillColorHexAria: "버튼 채움 색상 HEX",
|
||||
|
||||
strokeColorLabel: "외곽선 색상",
|
||||
strokeColorPickerAria: "버튼 외곽선 색상 피커",
|
||||
strokeColorHexAria: "버튼 외곽선 색상 HEX",
|
||||
|
||||
borderRadiusLabel: "모서리 둥글기",
|
||||
borderRadiusPresetNone: "없음",
|
||||
borderRadiusPresetSmall: "작게",
|
||||
borderRadiusPresetMedium: "보통",
|
||||
borderRadiusPresetLarge: "크게",
|
||||
borderRadiusPresetFull: "완전 둥글게",
|
||||
|
||||
widthModeLabel: "버튼 너비 모드",
|
||||
widthModeAria: "버튼 너비 모드",
|
||||
widthModeOptionAuto: "자동",
|
||||
widthModeOptionFull: "전체 폭",
|
||||
widthModeOptionFixed: "고정 값",
|
||||
|
||||
fixedWidthLabel: "버튼 고정 너비",
|
||||
fixedWidthUnitLabel: "(px)",
|
||||
fixedWidthPresetSmall: "작게",
|
||||
fixedWidthPresetMedium: "보통",
|
||||
fixedWidthPresetLarge: "넓게",
|
||||
|
||||
fontSizeLabel: "버튼 크기",
|
||||
fontSizeUnitLabel: "(px)",
|
||||
|
||||
lineHeightLabel: "줄 간격",
|
||||
lineHeightPresetTight: "좁게",
|
||||
lineHeightPresetNormal: "보통",
|
||||
lineHeightPresetRelaxed: "넓게",
|
||||
|
||||
letterSpacingLabel: "글자 간격",
|
||||
letterSpacingUnitLabel: "(px)",
|
||||
letterSpacingPresetTighter: "아주 좁게",
|
||||
letterSpacingPresetTight: "좁게",
|
||||
letterSpacingPresetNormal: "보통",
|
||||
letterSpacingPresetWide: "넓게",
|
||||
letterSpacingPresetWider: "아주 넓게",
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorButtonPanelMessages(
|
||||
locale: AppLocale | null | undefined,
|
||||
): EditorButtonPanelMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_BUTTON_PANEL_MESSAGES[key] ?? EDITOR_BUTTON_PANEL_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorCanvasMessages = {
|
||||
emptyStateHint: string;
|
||||
previewFallbackTextBlock: string;
|
||||
previewFallbackButtonBlock: string;
|
||||
previewFallbackImageBlock: string;
|
||||
previewFallbackListBlock: string;
|
||||
previewFallbackDividerBlock: string;
|
||||
previewFallbackSectionBlock: string;
|
||||
};
|
||||
|
||||
const EDITOR_CANVAS_MESSAGES: Record<AppLocale, EditorCanvasMessages> = {
|
||||
en: {
|
||||
emptyStateHint: 'Click the "Text" button on the left to add your first block.',
|
||||
previewFallbackTextBlock: "Text block",
|
||||
previewFallbackButtonBlock: "Button block",
|
||||
previewFallbackImageBlock: "Image block",
|
||||
previewFallbackListBlock: "List block",
|
||||
previewFallbackDividerBlock: "Divider block",
|
||||
previewFallbackSectionBlock: "Section block",
|
||||
},
|
||||
ko: {
|
||||
emptyStateHint: '왼쪽에서 "텍스트" 버튼을 눌러 블록을 추가해 보세요.',
|
||||
previewFallbackTextBlock: "텍스트 블록",
|
||||
previewFallbackButtonBlock: "버튼 블록",
|
||||
previewFallbackImageBlock: "이미지 블록",
|
||||
previewFallbackListBlock: "리스트 블록",
|
||||
previewFallbackDividerBlock: "구분선 블록",
|
||||
previewFallbackSectionBlock: "섹션 블록",
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorCanvasMessages(
|
||||
locale: AppLocale | null | undefined,
|
||||
): EditorCanvasMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_CANVAS_MESSAGES[key] ?? EDITOR_CANVAS_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorColorPickerFieldMessages = {
|
||||
dropdownLabelDefault: string;
|
||||
hexPlaceholder: string;
|
||||
paletteLabels: Record<string, string>;
|
||||
};
|
||||
|
||||
const EDITOR_COLOR_PICKER_FIELD_MESSAGES: Record<AppLocale, EditorColorPickerFieldMessages> = {
|
||||
en: {
|
||||
dropdownLabelDefault: "Color palette",
|
||||
hexPlaceholder: "e.g. #ff0000",
|
||||
paletteLabels: {
|
||||
default: "None",
|
||||
transparent: "Transparent",
|
||||
muted: "Muted",
|
||||
strong: "Strong highlight",
|
||||
neutral: "Neutral",
|
||||
accent: "Accent",
|
||||
"accent-deep": "Accent (deep)",
|
||||
"accent-soft": "Accent (soft)",
|
||||
danger: "Danger",
|
||||
"danger-deep": "Danger (strong)",
|
||||
success: "Success",
|
||||
"success-soft": "Success (soft)",
|
||||
warning: "Warning",
|
||||
info: "Info",
|
||||
purple: "Purple",
|
||||
"purple-soft": "Purple (soft)",
|
||||
pink: "Pink",
|
||||
"pink-soft": "Pink (soft)",
|
||||
dark: "Dark text",
|
||||
"dark-muted": "Dark muted",
|
||||
},
|
||||
},
|
||||
ko: {
|
||||
dropdownLabelDefault: "색상 팔레트",
|
||||
hexPlaceholder: "예: #ff0000",
|
||||
paletteLabels: {
|
||||
default: "없음",
|
||||
transparent: "투명",
|
||||
muted: "연한",
|
||||
strong: "강조",
|
||||
neutral: "중립",
|
||||
accent: "포인트",
|
||||
"accent-deep": "포인트 진하게",
|
||||
"accent-soft": "포인트 연하게",
|
||||
danger: "위험",
|
||||
"danger-deep": "위험 진하게",
|
||||
success: "성공",
|
||||
"success-soft": "성공 연하게",
|
||||
warning: "경고",
|
||||
info: "정보",
|
||||
purple: "보라",
|
||||
"purple-soft": "연한 보라",
|
||||
pink: "핑크",
|
||||
"pink-soft": "연한 핑크",
|
||||
dark: "어두운 텍스트",
|
||||
"dark-muted": "어두운 연한",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorColorPickerFieldMessages(
|
||||
locale: AppLocale | null | undefined,
|
||||
): EditorColorPickerFieldMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_COLOR_PICKER_FIELD_MESSAGES[key] ?? EDITOR_COLOR_PICKER_FIELD_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorDividerPropertiesPanelMessages = {
|
||||
alignLabel: string;
|
||||
alignAria: string;
|
||||
alignOptionLeft: string;
|
||||
alignOptionCenter: string;
|
||||
alignOptionRight: string;
|
||||
|
||||
thicknessLabel: string;
|
||||
thicknessAria: string;
|
||||
thicknessOptionThin: string;
|
||||
thicknessOptionMedium: string;
|
||||
|
||||
styleSectionTitle: string;
|
||||
|
||||
lengthModeLabel: string;
|
||||
lengthModeAria: string;
|
||||
lengthModeOptionAuto: string;
|
||||
lengthModeOptionFull: string;
|
||||
lengthModeOptionFixed: string;
|
||||
|
||||
fixedLengthLabel: string;
|
||||
fixedLengthUnitLabel: string;
|
||||
fixedLengthPresetShort: string;
|
||||
fixedLengthPresetNormal: string;
|
||||
fixedLengthPresetLong: string;
|
||||
|
||||
colorLabel: string;
|
||||
colorPickerAria: string;
|
||||
colorHexAria: string;
|
||||
|
||||
marginLabel: string;
|
||||
marginUnitLabel: string;
|
||||
marginPresetSmall: string;
|
||||
marginPresetNormal: string;
|
||||
marginPresetLarge: string;
|
||||
};
|
||||
|
||||
const EDITOR_DIVIDER_PROPERTIES_PANEL_MESSAGES: Record<AppLocale, EditorDividerPropertiesPanelMessages> = {
|
||||
en: {
|
||||
alignLabel: "Alignment",
|
||||
alignAria: "Divider alignment",
|
||||
alignOptionLeft: "Left",
|
||||
alignOptionCenter: "Center",
|
||||
alignOptionRight: "Right",
|
||||
|
||||
thicknessLabel: "Thickness",
|
||||
thicknessAria: "Divider thickness",
|
||||
thicknessOptionThin: "Thin",
|
||||
thicknessOptionMedium: "Normal",
|
||||
|
||||
styleSectionTitle: "Divider style",
|
||||
|
||||
lengthModeLabel: "Length mode",
|
||||
lengthModeAria: "Divider length mode",
|
||||
lengthModeOptionAuto: "Fit content",
|
||||
lengthModeOptionFull: "Full width",
|
||||
lengthModeOptionFixed: "Fixed length (px)",
|
||||
|
||||
fixedLengthLabel: "Fixed length (px)",
|
||||
fixedLengthUnitLabel: "(px)",
|
||||
fixedLengthPresetShort: "Short",
|
||||
fixedLengthPresetNormal: "Normal",
|
||||
fixedLengthPresetLong: "Long",
|
||||
|
||||
colorLabel: "Line color",
|
||||
colorPickerAria: "Divider color picker",
|
||||
colorHexAria: "Divider color HEX",
|
||||
|
||||
marginLabel: "Vertical margin",
|
||||
marginUnitLabel: "(px)",
|
||||
marginPresetSmall: "Small",
|
||||
marginPresetNormal: "Normal",
|
||||
marginPresetLarge: "Large",
|
||||
},
|
||||
|
||||
ko: {
|
||||
alignLabel: "정렬",
|
||||
alignAria: "구분선 정렬",
|
||||
alignOptionLeft: "왼쪽",
|
||||
alignOptionCenter: "가운데",
|
||||
alignOptionRight: "오른쪽",
|
||||
|
||||
thicknessLabel: "두께",
|
||||
thicknessAria: "구분선 두께",
|
||||
thicknessOptionThin: "얇게",
|
||||
thicknessOptionMedium: "보통",
|
||||
|
||||
styleSectionTitle: "구분선 스타일",
|
||||
|
||||
lengthModeLabel: "길이 모드",
|
||||
lengthModeAria: "구분선 길이 모드",
|
||||
lengthModeOptionAuto: "내용에 맞춤",
|
||||
lengthModeOptionFull: "전체 폭",
|
||||
lengthModeOptionFixed: "고정 길이 (px)",
|
||||
|
||||
fixedLengthLabel: "고정 길이 (px)",
|
||||
fixedLengthUnitLabel: "(px)",
|
||||
fixedLengthPresetShort: "짧게",
|
||||
fixedLengthPresetNormal: "보통",
|
||||
fixedLengthPresetLong: "길게",
|
||||
|
||||
colorLabel: "선 색상",
|
||||
colorPickerAria: "구분선 색상 피커",
|
||||
colorHexAria: "구분선 색상 HEX",
|
||||
|
||||
marginLabel: "위/아래 여백",
|
||||
marginUnitLabel: "(px)",
|
||||
marginPresetSmall: "작게",
|
||||
marginPresetNormal: "보통",
|
||||
marginPresetLarge: "크게",
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorDividerPropertiesPanelMessages(
|
||||
locale: AppLocale | null | undefined,
|
||||
): EditorDividerPropertiesPanelMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_DIVIDER_PROPERTIES_PANEL_MESSAGES[key] ?? EDITOR_DIVIDER_PROPERTIES_PANEL_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,298 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorFormCheckboxPanelMessages = {
|
||||
sectionTitle: string;
|
||||
|
||||
groupTitleTypeLabel: string;
|
||||
groupTitleTypeOptionText: string;
|
||||
groupTitleTypeOptionImage: string;
|
||||
|
||||
groupTitleDisplayLabel: string;
|
||||
groupTitleDisplayOptionVisible: string;
|
||||
groupTitleDisplayOptionHidden: string;
|
||||
|
||||
layoutLabel: string;
|
||||
layoutOptionStacked: string;
|
||||
layoutOptionInline: string;
|
||||
|
||||
optionLayoutLabel: string;
|
||||
optionLayoutOptionStacked: string;
|
||||
optionLayoutOptionInline: string;
|
||||
|
||||
labelGapLabel: string;
|
||||
|
||||
groupTitleLabel: string;
|
||||
|
||||
submitKeyLabel: string;
|
||||
|
||||
optionsLabel: string;
|
||||
addOptionButtonLabel: string;
|
||||
optionLabelPlaceholder: string;
|
||||
optionValuePlaceholder: string;
|
||||
|
||||
optionImageSourceLabel: string;
|
||||
optionImageSourceOptionUrl: string;
|
||||
optionImageSourceOptionUpload: string;
|
||||
|
||||
optionImageUrlPlaceholder: string;
|
||||
optionImageUploadLabel: string;
|
||||
optionImageUploadAria: string;
|
||||
|
||||
groupTitleImageSourceLabel: string;
|
||||
groupTitleImageSourceOptionUrl: string;
|
||||
groupTitleImageSourceOptionUpload: string;
|
||||
|
||||
groupTitleImageUrlLabel: string;
|
||||
groupTitleImageUploadLabel: string;
|
||||
groupTitleImageUploadAria: string;
|
||||
|
||||
requiredNoticeText: string;
|
||||
|
||||
styleSectionTitle: string;
|
||||
|
||||
textSizeLabel: string;
|
||||
textSizeUnitLabel: string;
|
||||
|
||||
lineHeightLabel: string;
|
||||
lineHeightUnitLabel: string;
|
||||
|
||||
letterSpacingLabel: string;
|
||||
letterSpacingUnitLabel: string;
|
||||
|
||||
widthModeLabel: string;
|
||||
widthModeOptionAuto: string;
|
||||
widthModeOptionFull: string;
|
||||
widthModeOptionFixed: string;
|
||||
|
||||
fixedWidthLabel: string;
|
||||
fixedWidthUnitLabel: string;
|
||||
|
||||
paddingXLabel: string;
|
||||
paddingXUnitLabel: string;
|
||||
|
||||
paddingYLabel: string;
|
||||
paddingYUnitLabel: string;
|
||||
|
||||
optionGapLabel: string;
|
||||
optionGapUnitLabel: string;
|
||||
|
||||
textColorLabel: string;
|
||||
textColorPickerAria: string;
|
||||
textColorHexAria: string;
|
||||
|
||||
fillColorLabel: string;
|
||||
fillColorPickerAria: string;
|
||||
fillColorHexAria: string;
|
||||
|
||||
strokeColorLabel: string;
|
||||
strokeColorPickerAria: string;
|
||||
strokeColorHexAria: string;
|
||||
|
||||
borderRadiusLabel: string;
|
||||
borderRadiusPresetNone: string;
|
||||
borderRadiusPresetSmall: string;
|
||||
borderRadiusPresetMedium: string;
|
||||
borderRadiusPresetLarge: string;
|
||||
borderRadiusPresetFull: string;
|
||||
};
|
||||
|
||||
const EDITOR_FORM_CHECKBOX_PANEL_MESSAGES: Record<AppLocale, EditorFormCheckboxPanelMessages> = {
|
||||
en: {
|
||||
sectionTitle: "Checkbox field",
|
||||
|
||||
groupTitleTypeLabel: "Group title type",
|
||||
groupTitleTypeOptionText: "Text",
|
||||
groupTitleTypeOptionImage: "Image",
|
||||
|
||||
groupTitleDisplayLabel: "Group title display mode",
|
||||
groupTitleDisplayOptionVisible: "Visible (default)",
|
||||
groupTitleDisplayOptionHidden: "Hidden",
|
||||
|
||||
layoutLabel: "Layout",
|
||||
layoutOptionStacked: "Vertical (default)",
|
||||
layoutOptionInline: "Horizontal (inline)",
|
||||
|
||||
optionLayoutLabel: "Option layout",
|
||||
optionLayoutOptionStacked: "Vertical (default)",
|
||||
optionLayoutOptionInline: "Horizontal (inline)",
|
||||
|
||||
labelGapLabel: "Label/field gap (px)",
|
||||
|
||||
groupTitleLabel: "Group title",
|
||||
|
||||
submitKeyLabel: "Submit key",
|
||||
|
||||
optionsLabel: "Options",
|
||||
addOptionButtonLabel: "Add option",
|
||||
optionLabelPlaceholder: "Label",
|
||||
optionValuePlaceholder: "Value (value)",
|
||||
|
||||
optionImageSourceLabel: "Option image source",
|
||||
optionImageSourceOptionUrl: "URL",
|
||||
optionImageSourceOptionUpload: "File upload",
|
||||
|
||||
optionImageUrlPlaceholder: "Option image URL (optional)",
|
||||
optionImageUploadLabel: "Option image file upload",
|
||||
optionImageUploadAria: "Option image file upload",
|
||||
|
||||
groupTitleImageSourceLabel: "Group title image source",
|
||||
groupTitleImageSourceOptionUrl: "URL",
|
||||
groupTitleImageSourceOptionUpload: "File upload",
|
||||
|
||||
groupTitleImageUrlLabel: "Group title image URL",
|
||||
groupTitleImageUploadLabel: "Group title image file upload",
|
||||
groupTitleImageUploadAria: "Group title image file upload",
|
||||
|
||||
requiredNoticeText: "Required state is configured in the form controller.",
|
||||
|
||||
styleSectionTitle: "Field style",
|
||||
|
||||
textSizeLabel: "Checkbox text size (px)",
|
||||
textSizeUnitLabel: "(px)",
|
||||
|
||||
lineHeightLabel: "Checkbox line height (px)",
|
||||
lineHeightUnitLabel: "(px)",
|
||||
|
||||
letterSpacingLabel: "Checkbox letter spacing (px)",
|
||||
letterSpacingUnitLabel: "(px)",
|
||||
|
||||
widthModeLabel: "Field width",
|
||||
widthModeOptionAuto: "Auto",
|
||||
widthModeOptionFull: "Full width",
|
||||
widthModeOptionFixed: "Fixed value",
|
||||
|
||||
fixedWidthLabel: "Field fixed width",
|
||||
fixedWidthUnitLabel: "(px)",
|
||||
|
||||
paddingXLabel: "Checkbox horizontal padding (px)",
|
||||
paddingXUnitLabel: "(px)",
|
||||
|
||||
paddingYLabel: "Checkbox vertical padding (px)",
|
||||
paddingYUnitLabel: "(px)",
|
||||
|
||||
optionGapLabel: "Checkbox option gap (px)",
|
||||
optionGapUnitLabel: "(px)",
|
||||
|
||||
textColorLabel: "Text color",
|
||||
textColorPickerAria: "Checkbox text color picker",
|
||||
textColorHexAria: "Checkbox text color HEX",
|
||||
|
||||
fillColorLabel: "Background color",
|
||||
fillColorPickerAria: "Checkbox background color picker",
|
||||
fillColorHexAria: "Checkbox background color HEX",
|
||||
|
||||
strokeColorLabel: "Border color",
|
||||
strokeColorPickerAria: "Checkbox border color picker",
|
||||
strokeColorHexAria: "Checkbox border color HEX",
|
||||
|
||||
borderRadiusLabel: "Field border radius",
|
||||
borderRadiusPresetNone: "None",
|
||||
borderRadiusPresetSmall: "Small",
|
||||
borderRadiusPresetMedium: "Medium",
|
||||
borderRadiusPresetLarge: "Large",
|
||||
borderRadiusPresetFull: "Fully rounded",
|
||||
},
|
||||
ko: {
|
||||
sectionTitle: "체크박스 필드",
|
||||
|
||||
groupTitleTypeLabel: "그룹 타이틀 타입",
|
||||
groupTitleTypeOptionText: "텍스트",
|
||||
groupTitleTypeOptionImage: "이미지",
|
||||
|
||||
groupTitleDisplayLabel: "그룹 타이틀 표시 방식",
|
||||
groupTitleDisplayOptionVisible: "표시 (기본)",
|
||||
groupTitleDisplayOptionHidden: "숨김",
|
||||
|
||||
layoutLabel: "레이아웃",
|
||||
layoutOptionStacked: "세로 (기본)",
|
||||
layoutOptionInline: "가로 (인라인)",
|
||||
|
||||
optionLayoutLabel: "옵션 레이아웃",
|
||||
optionLayoutOptionStacked: "세로 (기본)",
|
||||
optionLayoutOptionInline: "가로 (인라인)",
|
||||
|
||||
labelGapLabel: "라벨/필드 간격 (px)",
|
||||
|
||||
groupTitleLabel: "그룹 타이틀",
|
||||
|
||||
submitKeyLabel: "전송 키",
|
||||
|
||||
optionsLabel: "옵션",
|
||||
addOptionButtonLabel: "옵션 추가",
|
||||
optionLabelPlaceholder: "라벨",
|
||||
optionValuePlaceholder: "값(value)",
|
||||
|
||||
optionImageSourceLabel: "옵션 이미지 소스",
|
||||
optionImageSourceOptionUrl: "URL",
|
||||
optionImageSourceOptionUpload: "파일 업로드",
|
||||
|
||||
optionImageUrlPlaceholder: "옵션 이미지 URL (선택)",
|
||||
optionImageUploadLabel: "옵션 이미지 파일 업로드",
|
||||
optionImageUploadAria: "옵션 이미지 파일 업로드",
|
||||
|
||||
groupTitleImageSourceLabel: "그룹 타이틀 이미지 소스",
|
||||
groupTitleImageSourceOptionUrl: "URL",
|
||||
groupTitleImageSourceOptionUpload: "파일 업로드",
|
||||
|
||||
groupTitleImageUrlLabel: "그룹 타이틀 이미지 URL",
|
||||
groupTitleImageUploadLabel: "그룹 타이틀 이미지 파일 업로드",
|
||||
groupTitleImageUploadAria: "그룹 타이틀 이미지 파일 업로드",
|
||||
|
||||
requiredNoticeText: "필수 여부는 폼 컨트롤러에서 설정합니다.",
|
||||
|
||||
styleSectionTitle: "필드 스타일",
|
||||
|
||||
textSizeLabel: "체크박스 텍스트 크기 (px)",
|
||||
textSizeUnitLabel: "(px)",
|
||||
|
||||
lineHeightLabel: "체크박스 줄간격 (px)",
|
||||
lineHeightUnitLabel: "(px)",
|
||||
|
||||
letterSpacingLabel: "체크박스 자간 (px)",
|
||||
letterSpacingUnitLabel: "(px)",
|
||||
|
||||
widthModeLabel: "필드 너비",
|
||||
widthModeOptionAuto: "자동",
|
||||
widthModeOptionFull: "전체 폭",
|
||||
widthModeOptionFixed: "고정 값",
|
||||
|
||||
fixedWidthLabel: "필드 고정 너비",
|
||||
fixedWidthUnitLabel: "(px)",
|
||||
|
||||
paddingXLabel: "체크박스 가로 패딩 (px)",
|
||||
paddingXUnitLabel: "(px)",
|
||||
|
||||
paddingYLabel: "체크박스 세로 패딩 (px)",
|
||||
paddingYUnitLabel: "(px)",
|
||||
|
||||
optionGapLabel: "체크박스 옵션 간격 (px)",
|
||||
optionGapUnitLabel: "(px)",
|
||||
|
||||
textColorLabel: "텍스트 색상",
|
||||
textColorPickerAria: "체크박스 텍스트 색상 피커",
|
||||
textColorHexAria: "체크박스 텍스트 색상 HEX",
|
||||
|
||||
fillColorLabel: "배경 색상",
|
||||
fillColorPickerAria: "체크박스 배경 색상 피커",
|
||||
fillColorHexAria: "체크박스 배경 색상 HEX",
|
||||
|
||||
strokeColorLabel: "테두리 색상",
|
||||
strokeColorPickerAria: "체크박스 테두리 색상 피커",
|
||||
strokeColorHexAria: "체크박스 테두리 색상 HEX",
|
||||
|
||||
borderRadiusLabel: "필드 모서리 둥글기",
|
||||
borderRadiusPresetNone: "없음",
|
||||
borderRadiusPresetSmall: "작게",
|
||||
borderRadiusPresetMedium: "보통",
|
||||
borderRadiusPresetLarge: "크게",
|
||||
borderRadiusPresetFull: "완전 둥글게",
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorFormCheckboxPanelMessages(
|
||||
locale: AppLocale | null | undefined,
|
||||
): EditorFormCheckboxPanelMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_FORM_CHECKBOX_PANEL_MESSAGES[key] ?? EDITOR_FORM_CHECKBOX_PANEL_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorFormControllerPanelMessages = {
|
||||
introTextPrefix: string;
|
||||
introTextSuffix: string;
|
||||
|
||||
submitTargetLabel: string;
|
||||
submitTargetOptionInternal: string;
|
||||
submitTargetOptionWebhook: string;
|
||||
|
||||
webhookUrlLabel: string;
|
||||
webhookUrlPlaceholder: string;
|
||||
|
||||
payloadFormatLabel: string;
|
||||
payloadFormatOptionForm: string;
|
||||
payloadFormatOptionJson: string;
|
||||
|
||||
httpMethodLabel: string;
|
||||
|
||||
authTokenLabel: string;
|
||||
authTokenPlaceholder: string;
|
||||
|
||||
extraParamsLabel: string;
|
||||
extraParamsPlaceholder: string;
|
||||
|
||||
layoutSectionTitle: string;
|
||||
formWidthModeLabel: string;
|
||||
formWidthModeOptionAuto: string;
|
||||
formWidthModeOptionFull: string;
|
||||
formWidthModeOptionFixed: string;
|
||||
|
||||
formFixedWidthLabel: string;
|
||||
|
||||
marginYLabel: string;
|
||||
marginYPresetNone: string;
|
||||
marginYPresetCompact: string;
|
||||
marginYPresetNormal: string;
|
||||
marginYPresetSpacious: string;
|
||||
|
||||
messagesSectionTitle: string;
|
||||
successMessageLabel: string;
|
||||
successMessagePlaceholder: string;
|
||||
errorMessageLabel: string;
|
||||
errorMessagePlaceholder: string;
|
||||
|
||||
controllerSectionTitle: string;
|
||||
fieldMappingLegend: string;
|
||||
fieldMappingAriaLabel: string;
|
||||
requiredLabel: string;
|
||||
|
||||
submitButtonLabel: string;
|
||||
submitButtonAriaLabel: string;
|
||||
|
||||
sheetsGuideButtonLabel: string;
|
||||
sheetsGuideHeading: string;
|
||||
sheetsGuideCloseAriaLabel: string;
|
||||
sheetsGuideIntro: string;
|
||||
sheetsGuideStep1: string;
|
||||
sheetsGuideStep2: string;
|
||||
sheetsGuideStep3: string;
|
||||
sheetsGuideExampleCodeLabel: string;
|
||||
};
|
||||
|
||||
const EDITOR_FORM_CONTROLLER_PANEL_MESSAGES: Record<AppLocale, EditorFormControllerPanelMessages> = {
|
||||
en: {
|
||||
introTextPrefix:
|
||||
"This form is first submitted to the ",
|
||||
introTextSuffix:
|
||||
" endpoint on the public page, then processed internally or forwarded to a webhook depending on the settings.",
|
||||
|
||||
submitTargetLabel: "Submit target",
|
||||
submitTargetOptionInternal: "Internal only (no webhook)",
|
||||
submitTargetOptionWebhook: "Forward to external webhook / Google Sheets",
|
||||
|
||||
webhookUrlLabel: "Webhook URL (e.g. Google Apps Script web app URL)",
|
||||
webhookUrlPlaceholder: "e.g. https://script.google.com/macros/s/.../exec",
|
||||
|
||||
payloadFormatLabel: "Payload format",
|
||||
payloadFormatOptionForm: "Form data (x-www-form-urlencoded)",
|
||||
payloadFormatOptionJson: "JSON (application/json)",
|
||||
|
||||
httpMethodLabel: "HTTP method",
|
||||
|
||||
authTokenLabel: "Authorization token (optional)",
|
||||
authTokenPlaceholder: "e.g. Bearer xxxxxx",
|
||||
|
||||
extraParamsLabel: "Additional parameters (key=value lines, separated by line breaks)",
|
||||
extraParamsPlaceholder: "e.g.\nsource=landing\nformId=contact-hero",
|
||||
|
||||
layoutSectionTitle: "Form layout",
|
||||
formWidthModeLabel: "Form width mode",
|
||||
formWidthModeOptionAuto: "Auto",
|
||||
formWidthModeOptionFull: "Full width",
|
||||
formWidthModeOptionFixed: "Fixed value",
|
||||
|
||||
formFixedWidthLabel: "Form fixed width (px)",
|
||||
|
||||
marginYLabel: "Form top/bottom margin (px)",
|
||||
marginYPresetNone: "None",
|
||||
marginYPresetCompact: "Compact",
|
||||
marginYPresetNormal: "Normal",
|
||||
marginYPresetSpacious: "Spacious",
|
||||
|
||||
messagesSectionTitle: "Form messages",
|
||||
successMessageLabel: "Success message",
|
||||
successMessagePlaceholder: "e.g. Your message has been sent successfully.",
|
||||
errorMessageLabel: "Error message",
|
||||
errorMessagePlaceholder: "e.g. An error occurred while submitting.",
|
||||
|
||||
controllerSectionTitle: "Form controller",
|
||||
fieldMappingLegend: "Form field mapping",
|
||||
fieldMappingAriaLabel: "Form field mapping",
|
||||
requiredLabel: "Required",
|
||||
|
||||
submitButtonLabel: "Submit button",
|
||||
submitButtonAriaLabel: "Submit button",
|
||||
|
||||
sheetsGuideButtonLabel: "Google Sheets integration guide",
|
||||
sheetsGuideHeading: "Google Sheets integration guide",
|
||||
sheetsGuideCloseAriaLabel: "Close Google Sheets integration guide",
|
||||
sheetsGuideIntro:
|
||||
"You must enter the Google Apps Script web app URL, not the spreadsheet URL itself. Follow the steps below to connect Google Sheets without writing code.",
|
||||
sheetsGuideStep1:
|
||||
"In Google Sheets, create a new spreadsheet and add headers like name, email, message in the first row.",
|
||||
sheetsGuideStep2:
|
||||
"From the menu, open \"Extensions → Apps Script\" and paste the example code below.",
|
||||
sheetsGuideStep3:
|
||||
"From \"Deploy → New deployment\", deploy as a web app and paste the issued web app URL (…/exec) into the Webhook URL field.",
|
||||
sheetsGuideExampleCodeLabel: "Example Apps Script code",
|
||||
},
|
||||
ko: {
|
||||
introTextPrefix:
|
||||
"이 폼은 퍼블릭 페이지에서 ",
|
||||
introTextSuffix:
|
||||
" 엔드포인트로 먼저 전송된 뒤, 설정에 따라 내부 처리 또는 Webhook 으로 전달됩니다.",
|
||||
|
||||
submitTargetLabel: "전송 대상",
|
||||
submitTargetOptionInternal: "서버 처리 전용 (Webhook 없이 사용)",
|
||||
submitTargetOptionWebhook: "외부 Webhook / Google Sheets 로 전달",
|
||||
|
||||
webhookUrlLabel: "Webhook URL (예: Google Apps Script 웹 앱 URL)",
|
||||
webhookUrlPlaceholder: "예: https://script.google.com/macros/s/.../exec",
|
||||
|
||||
payloadFormatLabel: "전송 포맷",
|
||||
payloadFormatOptionForm: "폼 데이터 (x-www-form-urlencoded)",
|
||||
payloadFormatOptionJson: "JSON (application/json)",
|
||||
|
||||
httpMethodLabel: "HTTP 메서드",
|
||||
|
||||
authTokenLabel: "Authorization 토큰 (옵션)",
|
||||
authTokenPlaceholder: "예: Bearer xxxxxx",
|
||||
|
||||
extraParamsLabel: "추가 파라미터 (key=value 형식, 줄바꿈으로 구분)",
|
||||
extraParamsPlaceholder: "예:\nsource=landing\nformId=contact-hero",
|
||||
|
||||
layoutSectionTitle: "폼 레이아웃",
|
||||
formWidthModeLabel: "폼 너비 모드",
|
||||
formWidthModeOptionAuto: "자동",
|
||||
formWidthModeOptionFull: "전체 폭",
|
||||
formWidthModeOptionFixed: "고정 값",
|
||||
|
||||
formFixedWidthLabel: "폼 고정 너비 (px)",
|
||||
|
||||
marginYLabel: "폼 위/아래 여백 (px)",
|
||||
marginYPresetNone: "없음",
|
||||
marginYPresetCompact: "좁게",
|
||||
marginYPresetNormal: "보통",
|
||||
marginYPresetSpacious: "넓게",
|
||||
|
||||
messagesSectionTitle: "폼 메시지",
|
||||
successMessageLabel: "성공 메시지",
|
||||
successMessagePlaceholder: "예: 성공적으로 전송되었습니다.",
|
||||
errorMessageLabel: "에러 메시지",
|
||||
errorMessagePlaceholder: "예: 전송 중 오류가 발생했습니다.",
|
||||
|
||||
controllerSectionTitle: "폼 컨트롤러",
|
||||
fieldMappingLegend: "폼 필드 매핑",
|
||||
fieldMappingAriaLabel: "폼 필드 매핑",
|
||||
requiredLabel: "필수",
|
||||
|
||||
submitButtonLabel: "Submit 버튼",
|
||||
submitButtonAriaLabel: "Submit 버튼",
|
||||
|
||||
sheetsGuideButtonLabel: "Google Sheets 연동 가이드",
|
||||
sheetsGuideHeading: "Google Sheets 연동 가이드",
|
||||
sheetsGuideCloseAriaLabel: "Google Sheets 연동 가이드 닫기",
|
||||
sheetsGuideIntro:
|
||||
"구글 시트 주소를 그대로 입력하는 것이 아니라, 시트에 연결된 Google Apps Script 웹 앱 URL 을 입력해야 합니다. 아래 순서를 따르면 코드를 잘 모르는 사용자도 연동할 수 있습니다.",
|
||||
sheetsGuideStep1:
|
||||
"Google Sheets 에서 새 스프레드시트를 만들고, 1행에 name, email, message 같은 헤더를 추가합니다.",
|
||||
sheetsGuideStep2:
|
||||
'시트 메뉴의 "확장 프로그램 → 앱스 스크립트" 를 열고 아래 예제 코드를 붙여넣습니다.',
|
||||
sheetsGuideStep3:
|
||||
'"배포 → 새 배포" 에서 웹 앱으로 배포한 뒤, 발급된 웹 앱 URL(…/exec) 을 Webhook URL 칸에 붙여넣습니다.',
|
||||
sheetsGuideExampleCodeLabel: "예시 Apps Script 코드",
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorFormControllerPanelMessages(
|
||||
locale: AppLocale | null | undefined,
|
||||
): EditorFormControllerPanelMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_FORM_CONTROLLER_PANEL_MESSAGES[key] ?? EDITOR_FORM_CONTROLLER_PANEL_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorFormInputPanelMessages = {
|
||||
sectionTitle: string;
|
||||
styleSectionTitle: string;
|
||||
|
||||
labelTypeLabel: string;
|
||||
labelTypeOptionText: string;
|
||||
labelTypeOptionImage: string;
|
||||
|
||||
fieldLabelLabel: string;
|
||||
|
||||
labelDisplayLabel: string;
|
||||
labelDisplayOptionVisible: string;
|
||||
labelDisplayOptionHidden: string;
|
||||
labelDisplayOptionFloating: string;
|
||||
|
||||
layoutLabel: string;
|
||||
layoutOptionStacked: string;
|
||||
layoutOptionInline: string;
|
||||
labelGapLabel: string;
|
||||
labelGapUnitLabel: string;
|
||||
|
||||
labelImageUrlLabel: string;
|
||||
labelImageAltLabel: string;
|
||||
|
||||
submitKeyLabel: string;
|
||||
|
||||
fieldTypeLabel: string;
|
||||
fieldTypeAria: string;
|
||||
fieldTypeOptionText: string;
|
||||
fieldTypeOptionEmail: string;
|
||||
fieldTypeOptionTextarea: string;
|
||||
|
||||
placeholderLabel: string;
|
||||
placeholderAria: string;
|
||||
|
||||
requiredNoticeText: string;
|
||||
|
||||
textSizeLabel: string;
|
||||
textSizeUnitLabel: string;
|
||||
|
||||
lineHeightLabel: string;
|
||||
lineHeightUnitLabel: string;
|
||||
|
||||
letterSpacingLabel: string;
|
||||
letterSpacingUnitLabel: string;
|
||||
|
||||
textAlignLabel: string;
|
||||
textAlignOptionLeft: string;
|
||||
textAlignOptionCenter: string;
|
||||
textAlignOptionRight: string;
|
||||
|
||||
widthModeLabel: string;
|
||||
widthModeAria: string;
|
||||
widthModeOptionAuto: string;
|
||||
widthModeOptionFull: string;
|
||||
widthModeOptionFixed: string;
|
||||
|
||||
fixedWidthLabel: string;
|
||||
fixedWidthUnitLabel: string;
|
||||
|
||||
paddingXLabel: string;
|
||||
paddingXUnitLabel: string;
|
||||
|
||||
paddingYLabel: string;
|
||||
paddingYUnitLabel: string;
|
||||
|
||||
textColorLabel: string;
|
||||
textColorPickerAria: string;
|
||||
textColorHexAria: string;
|
||||
|
||||
fillColorLabel: string;
|
||||
fillColorPickerAria: string;
|
||||
fillColorHexAria: string;
|
||||
|
||||
strokeColorLabel: string;
|
||||
strokeColorPickerAria: string;
|
||||
strokeColorHexAria: string;
|
||||
|
||||
borderRadiusLabel: string;
|
||||
borderRadiusPresetNone: string;
|
||||
borderRadiusPresetSmall: string;
|
||||
borderRadiusPresetMedium: string;
|
||||
borderRadiusPresetLarge: string;
|
||||
borderRadiusPresetFull: string;
|
||||
};
|
||||
|
||||
const EDITOR_FORM_INPUT_PANEL_MESSAGES: Record<AppLocale, EditorFormInputPanelMessages> = {
|
||||
en: {
|
||||
sectionTitle: "Input field",
|
||||
styleSectionTitle: "Field style",
|
||||
|
||||
labelTypeLabel: "Label type",
|
||||
labelTypeOptionText: "Text",
|
||||
labelTypeOptionImage: "Image",
|
||||
|
||||
fieldLabelLabel: "Field label",
|
||||
|
||||
labelDisplayLabel: "Label display mode",
|
||||
labelDisplayOptionVisible: "Visible (default)",
|
||||
labelDisplayOptionHidden: "Hidden",
|
||||
labelDisplayOptionFloating: "Floating label",
|
||||
|
||||
layoutLabel: "Layout",
|
||||
layoutOptionStacked: "Vertical (default)",
|
||||
layoutOptionInline: "Horizontal (inline)",
|
||||
labelGapLabel: "Label/field gap (px)",
|
||||
labelGapUnitLabel: "(px)",
|
||||
|
||||
labelImageUrlLabel: "Label image URL",
|
||||
labelImageAltLabel: "Label image alt text",
|
||||
|
||||
submitKeyLabel: "Submit key",
|
||||
|
||||
fieldTypeLabel: "Field type",
|
||||
fieldTypeAria: "Field type",
|
||||
fieldTypeOptionText: "Text",
|
||||
fieldTypeOptionEmail: "Email",
|
||||
fieldTypeOptionTextarea: "Multiline text",
|
||||
|
||||
placeholderLabel: "Placeholder",
|
||||
placeholderAria: "Placeholder",
|
||||
|
||||
requiredNoticeText: "Required state is configured in the form controller.",
|
||||
|
||||
textSizeLabel: "Field text size (px)",
|
||||
textSizeUnitLabel: "(px)",
|
||||
|
||||
lineHeightLabel: "Field line height (px)",
|
||||
lineHeightUnitLabel: "(px)",
|
||||
|
||||
letterSpacingLabel: "Field letter spacing (px)",
|
||||
letterSpacingUnitLabel: "(px)",
|
||||
|
||||
textAlignLabel: "Text alignment",
|
||||
textAlignOptionLeft: "Left",
|
||||
textAlignOptionCenter: "Center",
|
||||
textAlignOptionRight: "Right",
|
||||
|
||||
widthModeLabel: "Width",
|
||||
widthModeAria: "Width",
|
||||
widthModeOptionAuto: "Auto",
|
||||
widthModeOptionFull: "Full width",
|
||||
widthModeOptionFixed: "Fixed value",
|
||||
|
||||
fixedWidthLabel: "Field fixed width",
|
||||
fixedWidthUnitLabel: "(px)",
|
||||
|
||||
paddingXLabel: "Field horizontal padding (px)",
|
||||
paddingXUnitLabel: "(px)",
|
||||
|
||||
paddingYLabel: "Field vertical padding (px)",
|
||||
paddingYUnitLabel: "(px)",
|
||||
|
||||
textColorLabel: "Field text color",
|
||||
textColorPickerAria: "Field text color picker",
|
||||
textColorHexAria: "Field text color HEX",
|
||||
|
||||
fillColorLabel: "Field fill color",
|
||||
fillColorPickerAria: "Field fill color picker",
|
||||
fillColorHexAria: "Field fill color HEX",
|
||||
|
||||
strokeColorLabel: "Field border color",
|
||||
strokeColorPickerAria: "Field border color picker",
|
||||
strokeColorHexAria: "Field border color HEX",
|
||||
|
||||
borderRadiusLabel: "Field border radius",
|
||||
borderRadiusPresetNone: "None",
|
||||
borderRadiusPresetSmall: "Small",
|
||||
borderRadiusPresetMedium: "Medium",
|
||||
borderRadiusPresetLarge: "Large",
|
||||
borderRadiusPresetFull: "Fully rounded",
|
||||
},
|
||||
ko: {
|
||||
sectionTitle: "입력 필드",
|
||||
styleSectionTitle: "필드 스타일",
|
||||
|
||||
labelTypeLabel: "라벨 타입",
|
||||
labelTypeOptionText: "텍스트",
|
||||
labelTypeOptionImage: "이미지",
|
||||
|
||||
fieldLabelLabel: "필드 라벨",
|
||||
|
||||
labelDisplayLabel: "라벨 표시 방식",
|
||||
labelDisplayOptionVisible: "표시 (기본)",
|
||||
labelDisplayOptionHidden: "숨김",
|
||||
labelDisplayOptionFloating: "플로팅 라벨",
|
||||
|
||||
layoutLabel: "레이아웃",
|
||||
layoutOptionStacked: "세로 (기본)",
|
||||
layoutOptionInline: "가로 (인라인)",
|
||||
labelGapLabel: "라벨/필드 간격 (px)",
|
||||
labelGapUnitLabel: "(px)",
|
||||
|
||||
labelImageUrlLabel: "라벨 이미지 URL",
|
||||
labelImageAltLabel: "라벨 이미지 대체 텍스트",
|
||||
|
||||
submitKeyLabel: "전송 키",
|
||||
|
||||
fieldTypeLabel: "필드 타입",
|
||||
fieldTypeAria: "필드 타입",
|
||||
fieldTypeOptionText: "텍스트",
|
||||
fieldTypeOptionEmail: "이메일",
|
||||
fieldTypeOptionTextarea: "긴 텍스트",
|
||||
|
||||
placeholderLabel: "Placeholder",
|
||||
placeholderAria: "Placeholder",
|
||||
|
||||
requiredNoticeText: "필수 여부는 폼 컨트롤러에서 설정합니다.",
|
||||
|
||||
textSizeLabel: "필드 텍스트 크기 (px)",
|
||||
textSizeUnitLabel: "(px)",
|
||||
|
||||
lineHeightLabel: "필드 줄간격 (px)",
|
||||
lineHeightUnitLabel: "(px)",
|
||||
|
||||
letterSpacingLabel: "필드 자간 (px)",
|
||||
letterSpacingUnitLabel: "(px)",
|
||||
|
||||
textAlignLabel: "텍스트 정렬",
|
||||
textAlignOptionLeft: "왼쪽",
|
||||
textAlignOptionCenter: "가운데",
|
||||
textAlignOptionRight: "오른쪽",
|
||||
|
||||
widthModeLabel: "너비",
|
||||
widthModeAria: "너비",
|
||||
widthModeOptionAuto: "자동",
|
||||
widthModeOptionFull: "전체 폭",
|
||||
widthModeOptionFixed: "고정 값",
|
||||
|
||||
fixedWidthLabel: "필드 고정 너비",
|
||||
fixedWidthUnitLabel: "(px)",
|
||||
|
||||
paddingXLabel: "필드 가로 패딩 (px)",
|
||||
paddingXUnitLabel: "(px)",
|
||||
|
||||
paddingYLabel: "필드 세로 패딩 (px)",
|
||||
paddingYUnitLabel: "(px)",
|
||||
|
||||
textColorLabel: "필드 텍스트 색상",
|
||||
textColorPickerAria: "필드 텍스트 색상 피커",
|
||||
textColorHexAria: "필드 텍스트 색상 HEX",
|
||||
|
||||
fillColorLabel: "필드 채움 색상",
|
||||
fillColorPickerAria: "필드 채움 색상 피커",
|
||||
fillColorHexAria: "필드 채움 색상 HEX",
|
||||
|
||||
strokeColorLabel: "필드 테두리 색상",
|
||||
strokeColorPickerAria: "필드 테두리 색상 피커",
|
||||
strokeColorHexAria: "필드 테두리 색상 HEX",
|
||||
|
||||
borderRadiusLabel: "필드 모서리 둥글기",
|
||||
borderRadiusPresetNone: "없음",
|
||||
borderRadiusPresetSmall: "작게",
|
||||
borderRadiusPresetMedium: "보통",
|
||||
borderRadiusPresetLarge: "크게",
|
||||
borderRadiusPresetFull: "완전 둥글게",
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorFormInputPanelMessages(locale: AppLocale | null | undefined): EditorFormInputPanelMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_FORM_INPUT_PANEL_MESSAGES[key] ?? EDITOR_FORM_INPUT_PANEL_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorFormRadioPanelMessages = {
|
||||
sectionTitle: string;
|
||||
|
||||
requiredNoticeText: string;
|
||||
|
||||
styleSectionTitle: string;
|
||||
|
||||
textSizeLabel: string;
|
||||
textSizeUnitLabel: string;
|
||||
|
||||
lineHeightLabel: string;
|
||||
lineHeightUnitLabel: string;
|
||||
|
||||
letterSpacingLabel: string;
|
||||
letterSpacingUnitLabel: string;
|
||||
|
||||
fixedWidthLabel: string;
|
||||
fixedWidthUnitLabel: string;
|
||||
|
||||
paddingXLabel: string;
|
||||
paddingXUnitLabel: string;
|
||||
|
||||
paddingYLabel: string;
|
||||
paddingYUnitLabel: string;
|
||||
|
||||
optionGapLabel: string;
|
||||
optionGapUnitLabel: string;
|
||||
|
||||
textColorLabel: string;
|
||||
textColorPickerAria: string;
|
||||
textColorHexAria: string;
|
||||
|
||||
fillColorLabel: string;
|
||||
fillColorPickerAria: string;
|
||||
fillColorHexAria: string;
|
||||
|
||||
strokeColorLabel: string;
|
||||
strokeColorPickerAria: string;
|
||||
strokeColorHexAria: string;
|
||||
|
||||
borderRadiusLabel: string;
|
||||
borderRadiusPresetNone: string;
|
||||
borderRadiusPresetSmall: string;
|
||||
borderRadiusPresetMedium: string;
|
||||
borderRadiusPresetLarge: string;
|
||||
borderRadiusPresetFull: string;
|
||||
};
|
||||
|
||||
const EDITOR_FORM_RADIO_PANEL_MESSAGES: Record<AppLocale, EditorFormRadioPanelMessages> = {
|
||||
en: {
|
||||
sectionTitle: "Radio field",
|
||||
|
||||
requiredNoticeText: "Required state is configured in the form controller.",
|
||||
|
||||
styleSectionTitle: "Field style",
|
||||
|
||||
textSizeLabel: "Radio text size (px)",
|
||||
textSizeUnitLabel: "(px)",
|
||||
|
||||
lineHeightLabel: "Radio line height (px)",
|
||||
lineHeightUnitLabel: "(px)",
|
||||
|
||||
letterSpacingLabel: "Radio letter spacing (px)",
|
||||
letterSpacingUnitLabel: "(px)",
|
||||
|
||||
fixedWidthLabel: "Field fixed width",
|
||||
fixedWidthUnitLabel: "(px)",
|
||||
|
||||
paddingXLabel: "Radio horizontal padding (px)",
|
||||
paddingXUnitLabel: "(px)",
|
||||
|
||||
paddingYLabel: "Radio vertical padding (px)",
|
||||
paddingYUnitLabel: "(px)",
|
||||
|
||||
optionGapLabel: "Radio option gap (px)",
|
||||
optionGapUnitLabel: "(px)",
|
||||
|
||||
textColorLabel: "Text color",
|
||||
textColorPickerAria: "Radio text color picker",
|
||||
textColorHexAria: "Radio text color HEX",
|
||||
|
||||
fillColorLabel: "Background color",
|
||||
fillColorPickerAria: "Radio background color picker",
|
||||
fillColorHexAria: "Radio background color HEX",
|
||||
|
||||
strokeColorLabel: "Border color",
|
||||
strokeColorPickerAria: "Radio border color picker",
|
||||
strokeColorHexAria: "Radio border color HEX",
|
||||
|
||||
borderRadiusLabel: "Field border radius",
|
||||
borderRadiusPresetNone: "None",
|
||||
borderRadiusPresetSmall: "Small",
|
||||
borderRadiusPresetMedium: "Medium",
|
||||
borderRadiusPresetLarge: "Large",
|
||||
borderRadiusPresetFull: "Fully rounded",
|
||||
},
|
||||
ko: {
|
||||
sectionTitle: "라디오 필드",
|
||||
|
||||
requiredNoticeText: "필수 여부는 폼 컨트롤러에서 설정합니다.",
|
||||
|
||||
styleSectionTitle: "필드 스타일",
|
||||
|
||||
textSizeLabel: "라디오 텍스트 크기 (px)",
|
||||
textSizeUnitLabel: "(px)",
|
||||
|
||||
lineHeightLabel: "라디오 줄간격 (px)",
|
||||
lineHeightUnitLabel: "(px)",
|
||||
|
||||
letterSpacingLabel: "라디오 자간 (px)",
|
||||
letterSpacingUnitLabel: "(px)",
|
||||
|
||||
fixedWidthLabel: "필드 고정 너비",
|
||||
fixedWidthUnitLabel: "(px)",
|
||||
|
||||
paddingXLabel: "라디오 가로 패딩 (px)",
|
||||
paddingXUnitLabel: "(px)",
|
||||
|
||||
paddingYLabel: "라디오 세로 패딩 (px)",
|
||||
paddingYUnitLabel: "(px)",
|
||||
|
||||
optionGapLabel: "라디오 옵션 간격 (px)",
|
||||
optionGapUnitLabel: "(px)",
|
||||
|
||||
textColorLabel: "텍스트 색상",
|
||||
textColorPickerAria: "라디오 텍스트 색상 피커",
|
||||
textColorHexAria: "라디오 텍스트 색상 HEX",
|
||||
|
||||
fillColorLabel: "배경 색상",
|
||||
fillColorPickerAria: "라디오 배경 색상 피커",
|
||||
fillColorHexAria: "라디오 배경 색상 HEX",
|
||||
|
||||
strokeColorLabel: "테두리 색상",
|
||||
strokeColorPickerAria: "라디오 테두리 색상 피커",
|
||||
strokeColorHexAria: "라디오 테두리 색상 HEX",
|
||||
|
||||
borderRadiusLabel: "필드 모서리 둥글기",
|
||||
borderRadiusPresetNone: "없음",
|
||||
borderRadiusPresetSmall: "작게",
|
||||
borderRadiusPresetMedium: "보통",
|
||||
borderRadiusPresetLarge: "크게",
|
||||
borderRadiusPresetFull: "완전 둥글게",
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorFormRadioPanelMessages(locale: AppLocale | null | undefined): EditorFormRadioPanelMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_FORM_RADIO_PANEL_MESSAGES[key] ?? EDITOR_FORM_RADIO_PANEL_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorFormSelectPanelMessages = {
|
||||
sectionTitle: string;
|
||||
|
||||
labelTypeLabel: string;
|
||||
labelTypeOptionText: string;
|
||||
labelTypeOptionImage: string;
|
||||
|
||||
labelDisplayLabel: string;
|
||||
labelDisplayOptionVisible: string;
|
||||
labelDisplayOptionHidden: string;
|
||||
|
||||
layoutLabel: string;
|
||||
layoutOptionStacked: string;
|
||||
layoutOptionInline: string;
|
||||
|
||||
labelGapLabel: string;
|
||||
|
||||
fieldLabelLabel: string;
|
||||
submitKeyLabel: string;
|
||||
|
||||
optionsLabel: string;
|
||||
addOptionButtonLabel: string;
|
||||
optionLabelPlaceholder: string;
|
||||
optionValuePlaceholder: string;
|
||||
|
||||
requiredNoticeText: string;
|
||||
|
||||
styleSectionTitle: string;
|
||||
|
||||
textSizeLabel: string;
|
||||
textSizeUnitLabel: string;
|
||||
|
||||
lineHeightLabel: string;
|
||||
lineHeightUnitLabel: string;
|
||||
|
||||
letterSpacingLabel: string;
|
||||
letterSpacingUnitLabel: string;
|
||||
|
||||
widthModeLabel: string;
|
||||
widthModeOptionAuto: string;
|
||||
widthModeOptionFull: string;
|
||||
widthModeOptionFixed: string;
|
||||
|
||||
fixedWidthLabel: string;
|
||||
fixedWidthUnitLabel: string;
|
||||
|
||||
paddingXLabel: string;
|
||||
paddingXUnitLabel: string;
|
||||
|
||||
paddingYLabel: string;
|
||||
paddingYUnitLabel: string;
|
||||
|
||||
textColorLabel: string;
|
||||
textColorPickerAria: string;
|
||||
textColorHexAria: string;
|
||||
|
||||
fillColorLabel: string;
|
||||
fillColorPickerAria: string;
|
||||
fillColorHexAria: string;
|
||||
|
||||
strokeColorLabel: string;
|
||||
strokeColorPickerAria: string;
|
||||
strokeColorHexAria: string;
|
||||
|
||||
borderRadiusLabel: string;
|
||||
borderRadiusPresetNone: string;
|
||||
borderRadiusPresetSmall: string;
|
||||
borderRadiusPresetMedium: string;
|
||||
borderRadiusPresetLarge: string;
|
||||
borderRadiusPresetFull: string;
|
||||
};
|
||||
|
||||
const EDITOR_FORM_SELECT_PANEL_MESSAGES: Record<AppLocale, EditorFormSelectPanelMessages> = {
|
||||
en: {
|
||||
sectionTitle: "Select field",
|
||||
|
||||
labelTypeLabel: "Label type",
|
||||
labelTypeOptionText: "Text",
|
||||
labelTypeOptionImage: "Image",
|
||||
|
||||
labelDisplayLabel: "Label display mode",
|
||||
labelDisplayOptionVisible: "Visible (default)",
|
||||
labelDisplayOptionHidden: "Hidden",
|
||||
|
||||
layoutLabel: "Layout",
|
||||
layoutOptionStacked: "Vertical (default)",
|
||||
layoutOptionInline: "Horizontal (inline)",
|
||||
|
||||
labelGapLabel: "Label/field gap (px)",
|
||||
|
||||
fieldLabelLabel: "Field label",
|
||||
submitKeyLabel: "Submit key",
|
||||
|
||||
optionsLabel: "Options",
|
||||
addOptionButtonLabel: "Add option",
|
||||
optionLabelPlaceholder: "Label",
|
||||
optionValuePlaceholder: "Value (value)",
|
||||
|
||||
requiredNoticeText: "Required state is configured in the form controller.",
|
||||
|
||||
styleSectionTitle: "Field style",
|
||||
|
||||
textSizeLabel: "Select text size (px)",
|
||||
textSizeUnitLabel: "(px)",
|
||||
|
||||
lineHeightLabel: "Select line height (px)",
|
||||
lineHeightUnitLabel: "(px)",
|
||||
|
||||
letterSpacingLabel: "Select letter spacing (px)",
|
||||
letterSpacingUnitLabel: "(px)",
|
||||
|
||||
widthModeLabel: "Field width",
|
||||
widthModeOptionAuto: "Auto",
|
||||
widthModeOptionFull: "Full width",
|
||||
widthModeOptionFixed: "Fixed value",
|
||||
|
||||
fixedWidthLabel: "Field fixed width",
|
||||
fixedWidthUnitLabel: "(px)",
|
||||
|
||||
paddingXLabel: "Select horizontal padding (px)",
|
||||
paddingXUnitLabel: "(px)",
|
||||
|
||||
paddingYLabel: "Select vertical padding (px)",
|
||||
paddingYUnitLabel: "(px)",
|
||||
|
||||
textColorLabel: "Field text color",
|
||||
textColorPickerAria: "Select text color picker",
|
||||
textColorHexAria: "Select text color HEX",
|
||||
|
||||
fillColorLabel: "Field fill color",
|
||||
fillColorPickerAria: "Select fill color picker",
|
||||
fillColorHexAria: "Select fill color HEX",
|
||||
|
||||
strokeColorLabel: "Field border color",
|
||||
strokeColorPickerAria: "Select border color picker",
|
||||
strokeColorHexAria: "Select border color HEX",
|
||||
|
||||
borderRadiusLabel: "Field border radius",
|
||||
borderRadiusPresetNone: "None",
|
||||
borderRadiusPresetSmall: "Small",
|
||||
borderRadiusPresetMedium: "Medium",
|
||||
borderRadiusPresetLarge: "Large",
|
||||
borderRadiusPresetFull: "Fully rounded",
|
||||
},
|
||||
ko: {
|
||||
sectionTitle: "셀렉트 필드",
|
||||
|
||||
labelTypeLabel: "라벨 타입",
|
||||
labelTypeOptionText: "텍스트",
|
||||
labelTypeOptionImage: "이미지",
|
||||
|
||||
labelDisplayLabel: "라벨 표시 방식",
|
||||
labelDisplayOptionVisible: "표시 (기본)",
|
||||
labelDisplayOptionHidden: "숨김",
|
||||
|
||||
layoutLabel: "레이아웃",
|
||||
layoutOptionStacked: "세로 (기본)",
|
||||
layoutOptionInline: "가로 (인라인)",
|
||||
|
||||
labelGapLabel: "라벨/필드 간격 (px)",
|
||||
|
||||
fieldLabelLabel: "필드 라벨",
|
||||
submitKeyLabel: "전송 키",
|
||||
|
||||
optionsLabel: "옵션",
|
||||
addOptionButtonLabel: "옵션 추가",
|
||||
optionLabelPlaceholder: "라벨",
|
||||
optionValuePlaceholder: "값(value)",
|
||||
|
||||
requiredNoticeText: "필수 여부는 폼 컨트롤러에서 설정합니다.",
|
||||
|
||||
styleSectionTitle: "필드 스타일",
|
||||
|
||||
textSizeLabel: "셀렉트 텍스트 크기 (px)",
|
||||
textSizeUnitLabel: "(px)",
|
||||
|
||||
lineHeightLabel: "셀렉트 줄간격 (px)",
|
||||
lineHeightUnitLabel: "(px)",
|
||||
|
||||
letterSpacingLabel: "셀렉트 자간 (px)",
|
||||
letterSpacingUnitLabel: "(px)",
|
||||
|
||||
widthModeLabel: "필드 너비",
|
||||
widthModeOptionAuto: "자동",
|
||||
widthModeOptionFull: "전체 폭",
|
||||
widthModeOptionFixed: "고정 값",
|
||||
|
||||
fixedWidthLabel: "필드 고정 너비",
|
||||
fixedWidthUnitLabel: "(px)",
|
||||
|
||||
paddingXLabel: "셀렉트 가로 패딩 (px)",
|
||||
paddingXUnitLabel: "(px)",
|
||||
|
||||
paddingYLabel: "셀렉트 세로 패딩 (px)",
|
||||
paddingYUnitLabel: "(px)",
|
||||
|
||||
textColorLabel: "필드 텍스트 색상",
|
||||
textColorPickerAria: "셀렉트 텍스트 색상 피커",
|
||||
textColorHexAria: "셀렉트 텍스트 색상 HEX",
|
||||
|
||||
fillColorLabel: "필드 채움 색상",
|
||||
fillColorPickerAria: "셀렉트 채움 색상 피커",
|
||||
fillColorHexAria: "셀렉트 채움 색상 HEX",
|
||||
|
||||
strokeColorLabel: "필드 테두리 색상",
|
||||
strokeColorPickerAria: "셀렉트 테두리 색상 피커",
|
||||
strokeColorHexAria: "셀렉트 테두리 색상 HEX",
|
||||
|
||||
borderRadiusLabel: "필드 모서리 둥글기",
|
||||
borderRadiusPresetNone: "없음",
|
||||
borderRadiusPresetSmall: "작게",
|
||||
borderRadiusPresetMedium: "보통",
|
||||
borderRadiusPresetLarge: "크게",
|
||||
borderRadiusPresetFull: "완전 둥글게",
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorFormSelectPanelMessages(
|
||||
locale: AppLocale | null | undefined,
|
||||
): EditorFormSelectPanelMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_FORM_SELECT_PANEL_MESSAGES[key] ?? EDITOR_FORM_SELECT_PANEL_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorImagePanelMessages = {
|
||||
imageSourceLabel: string;
|
||||
imageSourceAria: string;
|
||||
imageSourceOptionUrl: string;
|
||||
imageSourceOptionUpload: string;
|
||||
|
||||
imageUrlLabel: string;
|
||||
imageUrlAria: string;
|
||||
|
||||
imageUploadLabel: string;
|
||||
imageUploadAria: string;
|
||||
|
||||
altLabel: string;
|
||||
altAria: string;
|
||||
|
||||
styleSectionTitle: string;
|
||||
|
||||
cardBackgroundLabel: string;
|
||||
cardBackgroundPickerAria: string;
|
||||
cardBackgroundHexAria: string;
|
||||
|
||||
alignLabel: string;
|
||||
alignAria: string;
|
||||
alignOptionLeft: string;
|
||||
alignOptionCenter: string;
|
||||
alignOptionRight: string;
|
||||
|
||||
widthModeLabel: string;
|
||||
widthModeAria: string;
|
||||
widthModeOptionAuto: string;
|
||||
widthModeOptionFixed: string;
|
||||
|
||||
fixedWidthLabel: string;
|
||||
fixedWidthUnitLabel: string;
|
||||
fixedWidthPresetSmall: string;
|
||||
fixedWidthPresetMedium: string;
|
||||
fixedWidthPresetLarge: string;
|
||||
|
||||
borderRadiusLabel: string;
|
||||
borderRadiusPresetNone: string;
|
||||
borderRadiusPresetSmall: string;
|
||||
borderRadiusPresetMedium: string;
|
||||
borderRadiusPresetLarge: string;
|
||||
borderRadiusPresetFull: string;
|
||||
};
|
||||
|
||||
const EDITOR_IMAGE_PANEL_MESSAGES: Record<AppLocale, EditorImagePanelMessages> = {
|
||||
en: {
|
||||
imageSourceLabel: "Image source",
|
||||
imageSourceAria: "Image source",
|
||||
imageSourceOptionUrl: "URL",
|
||||
imageSourceOptionUpload: "File upload",
|
||||
|
||||
imageUrlLabel: "Image URL",
|
||||
imageUrlAria: "Image URL",
|
||||
|
||||
imageUploadLabel: "Image file upload",
|
||||
imageUploadAria: "Image file upload",
|
||||
|
||||
altLabel: "Alt text",
|
||||
altAria: "Alt text",
|
||||
|
||||
styleSectionTitle: "Image style",
|
||||
|
||||
cardBackgroundLabel: "Card background color",
|
||||
cardBackgroundPickerAria: "Image card background color picker",
|
||||
cardBackgroundHexAria: "Image card background color HEX",
|
||||
|
||||
alignLabel: "Alignment",
|
||||
alignAria: "Image alignment",
|
||||
alignOptionLeft: "Left",
|
||||
alignOptionCenter: "Center",
|
||||
alignOptionRight: "Right",
|
||||
|
||||
widthModeLabel: "Width mode",
|
||||
widthModeAria: "Image width mode",
|
||||
widthModeOptionAuto: "Fit to content",
|
||||
widthModeOptionFixed: "Fixed width (px)",
|
||||
|
||||
fixedWidthLabel: "Fixed width (px)",
|
||||
fixedWidthUnitLabel: "(px)",
|
||||
fixedWidthPresetSmall: "Small",
|
||||
fixedWidthPresetMedium: "Medium",
|
||||
fixedWidthPresetLarge: "Wide",
|
||||
|
||||
borderRadiusLabel: "Border radius",
|
||||
borderRadiusPresetNone: "None",
|
||||
borderRadiusPresetSmall: "Small",
|
||||
borderRadiusPresetMedium: "Medium",
|
||||
borderRadiusPresetLarge: "Large",
|
||||
borderRadiusPresetFull: "Fully rounded",
|
||||
},
|
||||
ko: {
|
||||
imageSourceLabel: "이미지 소스",
|
||||
imageSourceAria: "이미지 소스",
|
||||
imageSourceOptionUrl: "URL",
|
||||
imageSourceOptionUpload: "파일 업로드",
|
||||
|
||||
imageUrlLabel: "이미지 URL",
|
||||
imageUrlAria: "이미지 URL",
|
||||
|
||||
imageUploadLabel: "이미지 파일 업로드",
|
||||
imageUploadAria: "이미지 파일 업로드",
|
||||
|
||||
altLabel: "대체 텍스트",
|
||||
altAria: "대체 텍스트",
|
||||
|
||||
styleSectionTitle: "이미지 스타일",
|
||||
|
||||
cardBackgroundLabel: "카드 배경색",
|
||||
cardBackgroundPickerAria: "이미지 카드 배경색 피커",
|
||||
cardBackgroundHexAria: "이미지 카드 배경색 HEX",
|
||||
|
||||
alignLabel: "정렬",
|
||||
alignAria: "이미지 정렬",
|
||||
alignOptionLeft: "왼쪽",
|
||||
alignOptionCenter: "가운데",
|
||||
alignOptionRight: "오른쪽",
|
||||
|
||||
widthModeLabel: "너비 모드",
|
||||
widthModeAria: "이미지 너비 모드",
|
||||
widthModeOptionAuto: "내용에 맞춤",
|
||||
widthModeOptionFixed: "고정 너비 (px)",
|
||||
|
||||
fixedWidthLabel: "고정 너비 (px)",
|
||||
fixedWidthUnitLabel: "(px)",
|
||||
fixedWidthPresetSmall: "작게",
|
||||
fixedWidthPresetMedium: "보통",
|
||||
fixedWidthPresetLarge: "넓게",
|
||||
|
||||
borderRadiusLabel: "모서리 둥글기",
|
||||
borderRadiusPresetNone: "없음",
|
||||
borderRadiusPresetSmall: "작게",
|
||||
borderRadiusPresetMedium: "보통",
|
||||
borderRadiusPresetLarge: "크게",
|
||||
borderRadiusPresetFull: "완전 둥글게",
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorImagePanelMessages(
|
||||
locale: AppLocale | null | undefined,
|
||||
): EditorImagePanelMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_IMAGE_PANEL_MESSAGES[key] ?? EDITOR_IMAGE_PANEL_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorListPanelMessages = {
|
||||
listItemsLabel: string;
|
||||
listItemsAria: string;
|
||||
|
||||
alignLabel: string;
|
||||
alignAria: string;
|
||||
alignOptionLeft: string;
|
||||
alignOptionCenter: string;
|
||||
alignOptionRight: string;
|
||||
|
||||
styleSectionTitle: string;
|
||||
|
||||
fontSizeLabel: string;
|
||||
fontSizeUnitLabel: string;
|
||||
fontSizePresetSmall: string;
|
||||
fontSizePresetMedium: string;
|
||||
fontSizePresetLarge: string;
|
||||
|
||||
lineHeightLabel: string;
|
||||
lineHeightPresetTight: string;
|
||||
lineHeightPresetNormal: string;
|
||||
lineHeightPresetRelaxed: string;
|
||||
|
||||
textColorLabel: string;
|
||||
textColorPickerAria: string;
|
||||
textColorHexAria: string;
|
||||
|
||||
backgroundColorLabel: string;
|
||||
backgroundColorPickerAria: string;
|
||||
backgroundColorHexAria: string;
|
||||
|
||||
bulletStyleLabel: string;
|
||||
bulletStyleAria: string;
|
||||
bulletStyleOptionDisc: string;
|
||||
bulletStyleOptionCircle: string;
|
||||
bulletStyleOptionSquare: string;
|
||||
bulletStyleOptionDecimal: string;
|
||||
bulletStyleOptionLowerAlpha: string;
|
||||
bulletStyleOptionUpperAlpha: string;
|
||||
bulletStyleOptionLowerRoman: string;
|
||||
bulletStyleOptionUpperRoman: string;
|
||||
bulletStyleOptionNone: string;
|
||||
|
||||
gapLabel: string;
|
||||
gapUnitLabel: string;
|
||||
gapPresetTight: string;
|
||||
gapPresetNormal: string;
|
||||
gapPresetRelaxed: string;
|
||||
};
|
||||
|
||||
const EDITOR_LIST_PANEL_MESSAGES: Record<AppLocale, EditorListPanelMessages> = {
|
||||
en: {
|
||||
listItemsLabel: "List items (separated by line breaks)",
|
||||
listItemsAria: "List items",
|
||||
|
||||
alignLabel: "Alignment",
|
||||
alignAria: "List alignment",
|
||||
alignOptionLeft: "Left",
|
||||
alignOptionCenter: "Center",
|
||||
alignOptionRight: "Right",
|
||||
|
||||
styleSectionTitle: "List style",
|
||||
|
||||
fontSizeLabel: "Font size (px)",
|
||||
fontSizeUnitLabel: "(px)",
|
||||
fontSizePresetSmall: "Small",
|
||||
fontSizePresetMedium: "Medium",
|
||||
fontSizePresetLarge: "Large",
|
||||
|
||||
lineHeightLabel: "Line height",
|
||||
lineHeightPresetTight: "Tight",
|
||||
lineHeightPresetNormal: "Normal",
|
||||
lineHeightPresetRelaxed: "Relaxed",
|
||||
|
||||
textColorLabel: "Text color",
|
||||
textColorPickerAria: "List text color picker",
|
||||
textColorHexAria: "List text color HEX",
|
||||
|
||||
backgroundColorLabel: "Block background color",
|
||||
backgroundColorPickerAria: "List background color picker",
|
||||
backgroundColorHexAria: "List background color HEX",
|
||||
|
||||
bulletStyleLabel: "Bullet style",
|
||||
bulletStyleAria: "List bullet style",
|
||||
bulletStyleOptionDisc: "Default (●)",
|
||||
bulletStyleOptionCircle: "Circle (○)",
|
||||
bulletStyleOptionSquare: "Square (■)",
|
||||
bulletStyleOptionDecimal: "Decimal (1.)",
|
||||
bulletStyleOptionLowerAlpha: "Lower alpha (a.)",
|
||||
bulletStyleOptionUpperAlpha: "Upper alpha (A.)",
|
||||
bulletStyleOptionLowerRoman: "Lower roman (i.)",
|
||||
bulletStyleOptionUpperRoman: "Upper roman (I.)",
|
||||
bulletStyleOptionNone: "None",
|
||||
|
||||
gapLabel: "Item gap (px)",
|
||||
gapUnitLabel: "(px)",
|
||||
gapPresetTight: "Tight",
|
||||
gapPresetNormal: "Normal",
|
||||
gapPresetRelaxed: "Relaxed",
|
||||
},
|
||||
ko: {
|
||||
listItemsLabel: "리스트 아이템 (줄바꿈으로 구분)",
|
||||
listItemsAria: "리스트 아이템들",
|
||||
|
||||
alignLabel: "정렬",
|
||||
alignAria: "리스트 정렬",
|
||||
alignOptionLeft: "왼쪽",
|
||||
alignOptionCenter: "가운데",
|
||||
alignOptionRight: "오른쪽",
|
||||
|
||||
styleSectionTitle: "리스트 스타일",
|
||||
|
||||
fontSizeLabel: "글자 크기 (px)",
|
||||
fontSizeUnitLabel: "(px)",
|
||||
fontSizePresetSmall: "작게",
|
||||
fontSizePresetMedium: "보통",
|
||||
fontSizePresetLarge: "크게",
|
||||
|
||||
lineHeightLabel: "줄 간격",
|
||||
lineHeightPresetTight: "좁게",
|
||||
lineHeightPresetNormal: "보통",
|
||||
lineHeightPresetRelaxed: "넓게",
|
||||
|
||||
textColorLabel: "텍스트 색상",
|
||||
textColorPickerAria: "리스트 텍스트 색상 피커",
|
||||
textColorHexAria: "리스트 텍스트 색상 HEX",
|
||||
|
||||
backgroundColorLabel: "블록 배경색",
|
||||
backgroundColorPickerAria: "리스트 배경색 피커",
|
||||
backgroundColorHexAria: "리스트 배경색 HEX",
|
||||
|
||||
bulletStyleLabel: "불릿 스타일",
|
||||
bulletStyleAria: "리스트 불릿 스타일",
|
||||
bulletStyleOptionDisc: "기본 (●)",
|
||||
bulletStyleOptionCircle: "원 (○)",
|
||||
bulletStyleOptionSquare: "사각 (■)",
|
||||
bulletStyleOptionDecimal: "숫자 (1.)",
|
||||
bulletStyleOptionLowerAlpha: "알파벳 소문자 (a.)",
|
||||
bulletStyleOptionUpperAlpha: "알파벳 대문자 (A.)",
|
||||
bulletStyleOptionLowerRoman: "로마 숫자 소문자 (i.)",
|
||||
bulletStyleOptionUpperRoman: "로마 숫자 대문자 (I.)",
|
||||
bulletStyleOptionNone: "없음",
|
||||
|
||||
gapLabel: "아이템 간 여백 (px)",
|
||||
gapUnitLabel: "(px)",
|
||||
gapPresetTight: "좁게",
|
||||
gapPresetNormal: "보통",
|
||||
gapPresetRelaxed: "넓게",
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorListPanelMessages(
|
||||
locale: AppLocale | null | undefined,
|
||||
): EditorListPanelMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_LIST_PANEL_MESSAGES[key] ?? EDITOR_LIST_PANEL_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorProjectPropertiesPanelMessages = {
|
||||
sectionTitle: string;
|
||||
|
||||
projectTitleLabel: string;
|
||||
projectTitleAria: string;
|
||||
|
||||
projectSlugLabel: string;
|
||||
projectSlugAria: string;
|
||||
|
||||
canvasWidthLabel: string;
|
||||
canvasWidthUnitLabel: string;
|
||||
canvasWidthPresetMobile: string;
|
||||
canvasWidthPresetTablet: string;
|
||||
canvasWidthPresetDesktop: string;
|
||||
|
||||
canvasBgLabel: string;
|
||||
canvasBgColorAria: string;
|
||||
canvasBgHexAria: string;
|
||||
|
||||
pageBgLabel: string;
|
||||
pageBgColorAria: string;
|
||||
pageBgHexAria: string;
|
||||
|
||||
seoSectionTitle: string;
|
||||
|
||||
seoTitleLabel: string;
|
||||
seoTitleAria: string;
|
||||
seoTitlePlaceholderFallback: string;
|
||||
|
||||
seoDescriptionLabel: string;
|
||||
seoDescriptionAria: string;
|
||||
seoDescriptionPlaceholder: string;
|
||||
|
||||
seoOgImageUrlLabel: string;
|
||||
seoOgImageUrlAria: string;
|
||||
seoOgImageUrlPlaceholder: string;
|
||||
|
||||
seoCanonicalUrlLabel: string;
|
||||
seoCanonicalUrlAria: string;
|
||||
seoCanonicalUrlPlaceholder: string;
|
||||
|
||||
seoNoIndexAria: string;
|
||||
seoNoIndexLabel: string;
|
||||
|
||||
headHtmlLabel: string;
|
||||
headHtmlAria: string;
|
||||
headHtmlPlaceholder: string;
|
||||
|
||||
trackingScriptLabel: string;
|
||||
trackingScriptAria: string;
|
||||
trackingScriptPlaceholder: string;
|
||||
};
|
||||
|
||||
const EDITOR_PROJECT_PROPERTIES_PANEL_MESSAGES: Record<AppLocale, EditorProjectPropertiesPanelMessages> = {
|
||||
en: {
|
||||
sectionTitle: "Project settings",
|
||||
|
||||
projectTitleLabel: "Project title",
|
||||
projectTitleAria: "Project title",
|
||||
|
||||
projectSlugLabel: "Project slug",
|
||||
projectSlugAria: "Project slug",
|
||||
|
||||
canvasWidthLabel: "Canvas width",
|
||||
canvasWidthUnitLabel: "(px)",
|
||||
canvasWidthPresetMobile: "Mobile (390px)",
|
||||
canvasWidthPresetTablet: "Tablet (768px)",
|
||||
canvasWidthPresetDesktop: "Desktop (1200px)",
|
||||
|
||||
canvasBgLabel: "Canvas background color",
|
||||
canvasBgColorAria: "Canvas background color",
|
||||
canvasBgHexAria: "Canvas background HEX",
|
||||
|
||||
pageBgLabel: "Page background color",
|
||||
pageBgColorAria: "Page background color",
|
||||
pageBgHexAria: "Page background HEX",
|
||||
|
||||
seoSectionTitle: "SEO / meta",
|
||||
|
||||
seoTitleLabel: "SEO title",
|
||||
seoTitleAria: "SEO title",
|
||||
seoTitlePlaceholderFallback: "Page title",
|
||||
|
||||
seoDescriptionLabel: "Meta description",
|
||||
seoDescriptionAria: "Meta description",
|
||||
seoDescriptionPlaceholder: "Enter a description for search engines and social sharing.",
|
||||
|
||||
seoOgImageUrlLabel: "OG/Twitter image URL",
|
||||
seoOgImageUrlAria: "OG/Twitter image URL",
|
||||
seoOgImageUrlPlaceholder: "e.g. https://example.com/og-image.png",
|
||||
|
||||
seoCanonicalUrlLabel: "Canonical URL",
|
||||
seoCanonicalUrlAria: "Canonical URL",
|
||||
seoCanonicalUrlPlaceholder: "e.g. https://example.com/landing",
|
||||
|
||||
seoNoIndexAria: "Hide from search engines (noindex)",
|
||||
seoNoIndexLabel: "Hide from search engines (noindex)",
|
||||
|
||||
headHtmlLabel: "Page head HTML",
|
||||
headHtmlAria: "Page head HTML",
|
||||
headHtmlPlaceholder: 'e.g. <meta name="description" content="..." />',
|
||||
|
||||
trackingScriptLabel: "Tracking script",
|
||||
trackingScriptAria: "Tracking script",
|
||||
trackingScriptPlaceholder: 'e.g. <script>/* GA, Pixel code */</script>',
|
||||
},
|
||||
|
||||
ko: {
|
||||
sectionTitle: "프로젝트 설정",
|
||||
|
||||
projectTitleLabel: "프로젝트 제목",
|
||||
projectTitleAria: "프로젝트 제목",
|
||||
|
||||
projectSlugLabel: "프로젝트 주소 (slug)",
|
||||
projectSlugAria: "프로젝트 주소 (slug)",
|
||||
|
||||
canvasWidthLabel: "캔버스 너비",
|
||||
canvasWidthUnitLabel: "(px)",
|
||||
canvasWidthPresetMobile: "모바일 (390px)",
|
||||
canvasWidthPresetTablet: "태블릿 (768px)",
|
||||
canvasWidthPresetDesktop: "데스크톱 (1200px)",
|
||||
|
||||
canvasBgLabel: "캔버스 배경색",
|
||||
canvasBgColorAria: "캔버스 배경색",
|
||||
canvasBgHexAria: "캔버스 배경색 HEX",
|
||||
|
||||
pageBgLabel: "페이지 배경색",
|
||||
pageBgColorAria: "페이지 배경색",
|
||||
pageBgHexAria: "페이지 배경색 HEX",
|
||||
|
||||
seoSectionTitle: "SEO / 메타",
|
||||
|
||||
seoTitleLabel: "SEO 타이틀",
|
||||
seoTitleAria: "SEO 타이틀",
|
||||
seoTitlePlaceholderFallback: "페이지 제목",
|
||||
|
||||
seoDescriptionLabel: "메타 디스크립션",
|
||||
seoDescriptionAria: "메타 디스크립션",
|
||||
seoDescriptionPlaceholder: "검색엔진 및 SNS 공유에 노출될 페이지 설명을 입력하세요.",
|
||||
|
||||
seoOgImageUrlLabel: "OG/Twitter 이미지 URL",
|
||||
seoOgImageUrlAria: "OG/Twitter 이미지 URL",
|
||||
seoOgImageUrlPlaceholder: "예: https://example.com/og-image.png",
|
||||
|
||||
seoCanonicalUrlLabel: "Canonical URL",
|
||||
seoCanonicalUrlAria: "Canonical URL",
|
||||
seoCanonicalUrlPlaceholder: "예: https://example.com/landing",
|
||||
|
||||
seoNoIndexAria: "검색 엔진에 노출하지 않기 (noindex)",
|
||||
seoNoIndexLabel: "검색 엔진에 노출하지 않기 (noindex)",
|
||||
|
||||
headHtmlLabel: "페이지 head HTML",
|
||||
headHtmlAria: "페이지 head HTML",
|
||||
headHtmlPlaceholder: '예: <meta name="description" content="..." />',
|
||||
|
||||
trackingScriptLabel: "추적 스크립트",
|
||||
trackingScriptAria: "추적 스크립트",
|
||||
trackingScriptPlaceholder: '예: <script>/* GA, Pixel 코드 */</script>',
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorProjectPropertiesPanelMessages(
|
||||
locale: AppLocale | null | undefined,
|
||||
): EditorProjectPropertiesPanelMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_PROJECT_PROPERTIES_PANEL_MESSAGES[key] ?? EDITOR_PROJECT_PROPERTIES_PANEL_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,301 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorSectionPanelMessages = {
|
||||
backgroundColorLabel: string;
|
||||
backgroundColorPickerAria: string;
|
||||
backgroundColorHexAria: string;
|
||||
|
||||
backgroundImageSourceLabel: string;
|
||||
backgroundImageSourceAria: string;
|
||||
backgroundImageSourceOptionNone: string;
|
||||
backgroundImageSourceOptionUrl: string;
|
||||
backgroundImageSourceOptionUpload: string;
|
||||
|
||||
backgroundImageUrlLabel: string;
|
||||
backgroundImageUrlAria: string;
|
||||
|
||||
backgroundImageUploadLabel: string;
|
||||
backgroundImageUploadAria: string;
|
||||
|
||||
backgroundImagePositionModeLabel: string;
|
||||
backgroundImagePositionModeAria: string;
|
||||
backgroundImagePositionModeOptionPreset: string;
|
||||
backgroundImagePositionModeOptionCustom: string;
|
||||
|
||||
backgroundImageSizeLabel: string;
|
||||
backgroundImageSizeAria: string;
|
||||
|
||||
backgroundImagePositionLabel: string;
|
||||
backgroundImagePositionAria: string;
|
||||
backgroundImagePositionOptionCenter: string;
|
||||
backgroundImagePositionOptionTop: string;
|
||||
backgroundImagePositionOptionBottom: string;
|
||||
backgroundImagePositionOptionLeft: string;
|
||||
backgroundImagePositionOptionRight: string;
|
||||
|
||||
backgroundImagePositionXLabel: string;
|
||||
backgroundImagePositionYLabel: string;
|
||||
|
||||
backgroundImageRepeatLabel: string;
|
||||
backgroundImageRepeatAria: string;
|
||||
backgroundImageRepeatOptionNone: string;
|
||||
backgroundImageRepeatOptionBoth: string;
|
||||
backgroundImageRepeatOptionX: string;
|
||||
backgroundImageRepeatOptionY: string;
|
||||
|
||||
backgroundVideoSourceLabel: string;
|
||||
backgroundVideoSourceAria: string;
|
||||
backgroundVideoSourceOptionNone: string;
|
||||
backgroundVideoSourceOptionUrl: string;
|
||||
backgroundVideoSourceOptionUpload: string;
|
||||
|
||||
backgroundVideoUrlLabel: string;
|
||||
backgroundVideoUrlAria: string;
|
||||
|
||||
backgroundVideoUploadLabel: string;
|
||||
backgroundVideoUploadAria: string;
|
||||
|
||||
paddingYLabel: string;
|
||||
paddingYUnitLabel: string;
|
||||
paddingYPresetExtraTight: string;
|
||||
paddingYPresetTight: string;
|
||||
paddingYPresetNormal: string;
|
||||
paddingYPresetRelaxed: string;
|
||||
paddingYPresetExtraRelaxed: string;
|
||||
|
||||
layoutSectionTitle: string;
|
||||
columnLayoutLabel: string;
|
||||
columnLayoutAria: string;
|
||||
columnLayoutOptionOneFull: string;
|
||||
columnLayoutOptionTwoEqual: string;
|
||||
columnLayoutOptionTwoOneTwo: string;
|
||||
columnLayoutOptionTwoTwoOne: string;
|
||||
columnLayoutOptionThreeEqual: string;
|
||||
columnLayoutOptionCustom: string;
|
||||
|
||||
maxWidthLabel: string;
|
||||
maxWidthUnitLabel: string;
|
||||
maxWidthPresetExtraNarrow: string;
|
||||
maxWidthPresetNarrow: string;
|
||||
maxWidthPresetNormal: string;
|
||||
maxWidthPresetWide: string;
|
||||
maxWidthPresetExtraWide: string;
|
||||
|
||||
gapXLabel: string;
|
||||
gapXUnitLabel: string;
|
||||
gapXPresetZero: string;
|
||||
gapXPresetTight: string;
|
||||
gapXPresetNormal: string;
|
||||
gapXPresetRelaxed: string;
|
||||
gapXPresetExtraRelaxed: string;
|
||||
gapXPresetMax: string;
|
||||
|
||||
alignItemsLabel: string;
|
||||
alignItemsAria: string;
|
||||
alignItemsOptionTop: string;
|
||||
alignItemsOptionCenter: string;
|
||||
alignItemsOptionBottom: string;
|
||||
};
|
||||
|
||||
const EDITOR_SECTION_PANEL_MESSAGES: Record<AppLocale, EditorSectionPanelMessages> = {
|
||||
en: {
|
||||
backgroundColorLabel: "Background color",
|
||||
backgroundColorPickerAria: "Section background color picker",
|
||||
backgroundColorHexAria: "Section background color HEX",
|
||||
|
||||
backgroundImageSourceLabel: "Background image source",
|
||||
backgroundImageSourceAria: "Background image source",
|
||||
backgroundImageSourceOptionNone: "None",
|
||||
backgroundImageSourceOptionUrl: "URL",
|
||||
backgroundImageSourceOptionUpload: "File upload",
|
||||
|
||||
backgroundImageUrlLabel: "Background image URL",
|
||||
backgroundImageUrlAria: "Background image URL",
|
||||
|
||||
backgroundImageUploadLabel: "Background image file upload",
|
||||
backgroundImageUploadAria: "Background image file upload",
|
||||
|
||||
backgroundImagePositionModeLabel: "Background image position mode",
|
||||
backgroundImagePositionModeAria: "Background image position mode",
|
||||
backgroundImagePositionModeOptionPreset: "Preset",
|
||||
backgroundImagePositionModeOptionCustom: "Custom (X/Y)",
|
||||
|
||||
backgroundImageSizeLabel: "Background image size",
|
||||
backgroundImageSizeAria: "Background image size",
|
||||
|
||||
backgroundImagePositionLabel: "Background image position",
|
||||
backgroundImagePositionAria: "Background image position",
|
||||
backgroundImagePositionOptionCenter: "Center",
|
||||
backgroundImagePositionOptionTop: "Top",
|
||||
backgroundImagePositionOptionBottom: "Bottom",
|
||||
backgroundImagePositionOptionLeft: "Left",
|
||||
backgroundImagePositionOptionRight: "Right",
|
||||
|
||||
backgroundImagePositionXLabel: "Background image horizontal position",
|
||||
backgroundImagePositionYLabel: "Background image vertical position",
|
||||
|
||||
backgroundImageRepeatLabel: "Background image repeat",
|
||||
backgroundImageRepeatAria: "Background image repeat",
|
||||
backgroundImageRepeatOptionNone: "No repeat",
|
||||
backgroundImageRepeatOptionBoth: "Repeat (x/y)",
|
||||
backgroundImageRepeatOptionX: "Repeat horizontally",
|
||||
backgroundImageRepeatOptionY: "Repeat vertically",
|
||||
|
||||
backgroundVideoSourceLabel: "Background video source",
|
||||
backgroundVideoSourceAria: "Background video source",
|
||||
backgroundVideoSourceOptionNone: "None",
|
||||
backgroundVideoSourceOptionUrl: "URL",
|
||||
backgroundVideoSourceOptionUpload: "File upload",
|
||||
|
||||
backgroundVideoUrlLabel: "Background video URL",
|
||||
backgroundVideoUrlAria: "Background video URL",
|
||||
|
||||
backgroundVideoUploadLabel: "Background video file upload",
|
||||
backgroundVideoUploadAria: "Background video file upload",
|
||||
|
||||
paddingYLabel: "Vertical padding",
|
||||
paddingYUnitLabel: "(px)",
|
||||
paddingYPresetExtraTight: "Very tight",
|
||||
paddingYPresetTight: "Tight",
|
||||
paddingYPresetNormal: "Normal",
|
||||
paddingYPresetRelaxed: "Wide",
|
||||
paddingYPresetExtraRelaxed: "Very wide",
|
||||
|
||||
layoutSectionTitle: "Section layout",
|
||||
columnLayoutLabel: "Section column layout",
|
||||
columnLayoutAria: "Section column layout",
|
||||
columnLayoutOptionOneFull: "1 column (1/1)",
|
||||
columnLayoutOptionTwoEqual: "2 columns (1/2 - 1/2)",
|
||||
columnLayoutOptionTwoOneTwo: "2 columns (1/3 - 2/3)",
|
||||
columnLayoutOptionTwoTwoOne: "2 columns (2/3 - 1/3)",
|
||||
columnLayoutOptionThreeEqual: "3 columns (1/3 - 1/3 - 1/3)",
|
||||
columnLayoutOptionCustom: "Custom",
|
||||
|
||||
maxWidthLabel: "Max width (px)",
|
||||
maxWidthUnitLabel: "(px)",
|
||||
maxWidthPresetExtraNarrow: "Very narrow",
|
||||
maxWidthPresetNarrow: "Narrow",
|
||||
maxWidthPresetNormal: "Normal",
|
||||
maxWidthPresetWide: "Wide",
|
||||
maxWidthPresetExtraWide: "Very wide",
|
||||
|
||||
gapXLabel: "Column gap (px)",
|
||||
gapXUnitLabel: "(px)",
|
||||
gapXPresetZero: "0",
|
||||
gapXPresetTight: "Tight",
|
||||
gapXPresetNormal: "Normal",
|
||||
gapXPresetRelaxed: "Wide",
|
||||
gapXPresetExtraRelaxed: "Very wide",
|
||||
gapXPresetMax: "Max",
|
||||
|
||||
alignItemsLabel: "Column vertical alignment",
|
||||
alignItemsAria: "Section column vertical alignment",
|
||||
alignItemsOptionTop: "Top",
|
||||
alignItemsOptionCenter: "Center",
|
||||
alignItemsOptionBottom: "Bottom",
|
||||
},
|
||||
ko: {
|
||||
backgroundColorLabel: "배경 색상",
|
||||
backgroundColorPickerAria: "섹션 배경 색상 선택",
|
||||
backgroundColorHexAria: "섹션 배경 색상 HEX 입력",
|
||||
|
||||
backgroundImageSourceLabel: "배경 이미지 소스",
|
||||
backgroundImageSourceAria: "배경 이미지 소스",
|
||||
backgroundImageSourceOptionNone: "없음",
|
||||
backgroundImageSourceOptionUrl: "URL",
|
||||
backgroundImageSourceOptionUpload: "파일 업로드",
|
||||
|
||||
backgroundImageUrlLabel: "배경 이미지 URL",
|
||||
backgroundImageUrlAria: "배경 이미지 URL",
|
||||
|
||||
backgroundImageUploadLabel: "배경 이미지 파일 업로드",
|
||||
backgroundImageUploadAria: "배경 이미지 파일 업로드",
|
||||
|
||||
backgroundImagePositionModeLabel: "배경 이미지 위치 모드",
|
||||
backgroundImagePositionModeAria: "배경 이미지 위치 모드",
|
||||
backgroundImagePositionModeOptionPreset: "프리셋",
|
||||
backgroundImagePositionModeOptionCustom: "커스텀 (X/Y)",
|
||||
|
||||
backgroundImageSizeLabel: "배경 이미지 크기",
|
||||
backgroundImageSizeAria: "배경 이미지 크기",
|
||||
|
||||
backgroundImagePositionLabel: "배경 이미지 위치",
|
||||
backgroundImagePositionAria: "배경 이미지 위치",
|
||||
backgroundImagePositionOptionCenter: "가운데",
|
||||
backgroundImagePositionOptionTop: "위",
|
||||
backgroundImagePositionOptionBottom: "아래",
|
||||
backgroundImagePositionOptionLeft: "왼쪽",
|
||||
backgroundImagePositionOptionRight: "오른쪽",
|
||||
|
||||
backgroundImagePositionXLabel: "배경 이미지 가로 위치",
|
||||
backgroundImagePositionYLabel: "배경 이미지 세로 위치",
|
||||
|
||||
backgroundImageRepeatLabel: "배경 이미지 반복",
|
||||
backgroundImageRepeatAria: "배경 이미지 반복",
|
||||
backgroundImageRepeatOptionNone: "반복 없음",
|
||||
backgroundImageRepeatOptionBoth: "가로/세로 반복",
|
||||
backgroundImageRepeatOptionX: "가로 반복",
|
||||
backgroundImageRepeatOptionY: "세로 반복",
|
||||
|
||||
backgroundVideoSourceLabel: "배경 비디오 소스",
|
||||
backgroundVideoSourceAria: "배경 비디오 소스",
|
||||
backgroundVideoSourceOptionNone: "없음",
|
||||
backgroundVideoSourceOptionUrl: "URL",
|
||||
backgroundVideoSourceOptionUpload: "파일 업로드",
|
||||
|
||||
backgroundVideoUrlLabel: "배경 비디오 URL",
|
||||
backgroundVideoUrlAria: "배경 비디오 URL",
|
||||
|
||||
backgroundVideoUploadLabel: "배경 비디오 파일 업로드",
|
||||
backgroundVideoUploadAria: "배경 비디오 파일 업로드",
|
||||
|
||||
paddingYLabel: "세로 패딩",
|
||||
paddingYUnitLabel: "(px)",
|
||||
paddingYPresetExtraTight: "매우 좁게",
|
||||
paddingYPresetTight: "좁게",
|
||||
paddingYPresetNormal: "보통",
|
||||
paddingYPresetRelaxed: "넓게",
|
||||
paddingYPresetExtraRelaxed: "아주 넓게",
|
||||
|
||||
layoutSectionTitle: "섹션 레이아웃",
|
||||
columnLayoutLabel: "섹션 컬럼 레이아웃",
|
||||
columnLayoutAria: "섹션 컬럼 레이아웃",
|
||||
columnLayoutOptionOneFull: "1열 (1/1)",
|
||||
columnLayoutOptionTwoEqual: "2열 (1/2 - 1/2)",
|
||||
columnLayoutOptionTwoOneTwo: "2열 (1/3 - 2/3)",
|
||||
columnLayoutOptionTwoTwoOne: "2열 (2/3 - 1/3)",
|
||||
columnLayoutOptionThreeEqual: "3열 (1/3 - 1/3 - 1/3)",
|
||||
columnLayoutOptionCustom: "직접 조정",
|
||||
|
||||
maxWidthLabel: "최대 폭 (px)",
|
||||
maxWidthUnitLabel: "(px)",
|
||||
maxWidthPresetExtraNarrow: "매우 좁게",
|
||||
maxWidthPresetNarrow: "좁게",
|
||||
maxWidthPresetNormal: "보통",
|
||||
maxWidthPresetWide: "넓게",
|
||||
maxWidthPresetExtraWide: "아주 넓게",
|
||||
|
||||
gapXLabel: "컬럼 간 간격 (px)",
|
||||
gapXUnitLabel: "(px)",
|
||||
gapXPresetZero: "0",
|
||||
gapXPresetTight: "좁게",
|
||||
gapXPresetNormal: "보통",
|
||||
gapXPresetRelaxed: "넓게",
|
||||
gapXPresetExtraRelaxed: "아주 넓게",
|
||||
gapXPresetMax: "최대",
|
||||
|
||||
alignItemsLabel: "컬럼 세로 정렬",
|
||||
alignItemsAria: "섹션 컬럼 세로 정렬",
|
||||
alignItemsOptionTop: "위",
|
||||
alignItemsOptionCenter: "가운데",
|
||||
alignItemsOptionBottom: "아래",
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorSectionPanelMessages(
|
||||
locale: AppLocale | null | undefined,
|
||||
): EditorSectionPanelMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_SECTION_PANEL_MESSAGES[key] ?? EDITOR_SECTION_PANEL_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,128 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorSidebarMessages = {
|
||||
blocksTitle: string;
|
||||
blocksText: string;
|
||||
blocksButton: string;
|
||||
blocksImage: string;
|
||||
blocksVideo: string;
|
||||
blocksDivider: string;
|
||||
blocksList: string;
|
||||
blocksSection: string;
|
||||
formsTitle: string;
|
||||
formsController: string;
|
||||
formsInput: string;
|
||||
formsSelect: string;
|
||||
formsRadio: string;
|
||||
formsCheckbox: string;
|
||||
templatesTitle: string;
|
||||
templatesGroupHeroCta: string;
|
||||
templatesGroupContent: string;
|
||||
templatesGroupTrust: string;
|
||||
templatesGroupFooter: string;
|
||||
templateHeroLabel: string;
|
||||
templateHeroDescription: string;
|
||||
templateCtaLabel: string;
|
||||
templateCtaDescription: string;
|
||||
templateFeaturesLabel: string;
|
||||
templateFeaturesDescription: string;
|
||||
templateFaqLabel: string;
|
||||
templateFaqDescription: string;
|
||||
templatePricingLabel: string;
|
||||
templatePricingDescription: string;
|
||||
templateBlogLabel: string;
|
||||
templateBlogDescription: string;
|
||||
templateTestimonialsLabel: string;
|
||||
templateTestimonialsDescription: string;
|
||||
templateTeamLabel: string;
|
||||
templateTeamDescription: string;
|
||||
templateFooterLabel: string;
|
||||
templateFooterDescription: string;
|
||||
};
|
||||
|
||||
const EDITOR_SIDEBAR_MESSAGES: Record<AppLocale, EditorSidebarMessages> = {
|
||||
en: {
|
||||
blocksTitle: "Blocks",
|
||||
blocksText: "Text",
|
||||
blocksButton: "Button",
|
||||
blocksImage: "Image",
|
||||
blocksVideo: "Video",
|
||||
blocksDivider: "Divider",
|
||||
blocksList: "List",
|
||||
blocksSection: "Section",
|
||||
formsTitle: "Form elements",
|
||||
formsController: "Form controller",
|
||||
formsInput: "Input field",
|
||||
formsSelect: "Select field",
|
||||
formsRadio: "Radio group",
|
||||
formsCheckbox: "Checkbox group",
|
||||
templatesTitle: "Templates",
|
||||
templatesGroupHeroCta: "Hero · CTA",
|
||||
templatesGroupContent: "Content sections",
|
||||
templatesGroupTrust: "Trust & about",
|
||||
templatesGroupFooter: "Footer & misc",
|
||||
templateHeroLabel: "Hero template",
|
||||
templateHeroDescription: "Top-of-page hero section (headline + subtext + button)",
|
||||
templateCtaLabel: "CTA template",
|
||||
templateCtaDescription: "Call-to-action (CTA) section",
|
||||
templateFeaturesLabel: "Features template",
|
||||
templateFeaturesDescription: "Three-column features section",
|
||||
templateFaqLabel: "FAQ template",
|
||||
templateFaqDescription: "Frequently asked questions (FAQ) section",
|
||||
templatePricingLabel: "Pricing template",
|
||||
templatePricingDescription: "Pricing plans section",
|
||||
templateBlogLabel: "Blog template",
|
||||
templateBlogDescription: "Blog post listing section",
|
||||
templateTestimonialsLabel: "Testimonials template",
|
||||
templateTestimonialsDescription: "Customer testimonials section",
|
||||
templateTeamLabel: "Team template",
|
||||
templateTeamDescription: "Team members section",
|
||||
templateFooterLabel: "Footer template",
|
||||
templateFooterDescription: "Page footer section",
|
||||
},
|
||||
ko: {
|
||||
blocksTitle: "블록",
|
||||
blocksText: "텍스트",
|
||||
blocksButton: "버튼",
|
||||
blocksImage: "이미지",
|
||||
blocksVideo: "비디오",
|
||||
blocksDivider: "구분선",
|
||||
blocksList: "리스트",
|
||||
blocksSection: "섹션",
|
||||
formsTitle: "폼 요소",
|
||||
formsController: "폼 컨트롤러",
|
||||
formsInput: "입력(Input)",
|
||||
formsSelect: "셀렉트(Select)",
|
||||
formsRadio: "단일 선택(Radio)",
|
||||
formsCheckbox: "다중 선택(Checkbox)",
|
||||
templatesTitle: "템플릿",
|
||||
templatesGroupHeroCta: "히어로 · CTA",
|
||||
templatesGroupContent: "콘텐츠 섹션",
|
||||
templatesGroupTrust: "신뢰/소개",
|
||||
templatesGroupFooter: "푸터/기타",
|
||||
templateHeroLabel: "Hero 템플릿",
|
||||
templateHeroDescription: "페이지 상단 Hero 섹션 (큰 제목 + 서브텍스트 + 버튼)",
|
||||
templateCtaLabel: "CTA 템플릿",
|
||||
templateCtaDescription: "콜투액션(CTA) 섹션",
|
||||
templateFeaturesLabel: "기능 템플릿",
|
||||
templateFeaturesDescription: "3컬럼 기능 소개 섹션",
|
||||
templateFaqLabel: "FAQ 템플릿",
|
||||
templateFaqDescription: "자주 묻는 질문(FAQ) 섹션",
|
||||
templatePricingLabel: "상품 템플릿",
|
||||
templatePricingDescription: "요금제/플랜 소개 섹션",
|
||||
templateBlogLabel: "블로그 템플릿",
|
||||
templateBlogDescription: "블로그 포스트 목록 섹션",
|
||||
templateTestimonialsLabel: "후기 템플릿",
|
||||
templateTestimonialsDescription: "고객 후기(Testimonials) 섹션",
|
||||
templateTeamLabel: "Team 템플릿",
|
||||
templateTeamDescription: "팀 소개 섹션",
|
||||
templateFooterLabel: "Footer 템플릿",
|
||||
templateFooterDescription: "페이지 푸터 섹션",
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorSidebarMessages(locale: AppLocale | null | undefined): EditorSidebarMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_SIDEBAR_MESSAGES[key] ?? EDITOR_SIDEBAR_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorHeroTemplateMessages = {
|
||||
headline: string;
|
||||
subheadline: string;
|
||||
primaryButtonLabel: string;
|
||||
};
|
||||
|
||||
export type EditorFeaturesTemplateMessages = {
|
||||
itemTitlePrefix: string;
|
||||
itemTitleSuffix: string;
|
||||
itemDescription: string;
|
||||
};
|
||||
|
||||
export type EditorCtaTemplateMessages = {
|
||||
body: string;
|
||||
buttonLabel: string;
|
||||
};
|
||||
|
||||
export type EditorFaqTemplateMessages = {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
items: Array<{
|
||||
question: string;
|
||||
answer: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type EditorPricingTemplateMessages = {
|
||||
plans: Array<{
|
||||
name: string;
|
||||
price: string;
|
||||
popular?: boolean;
|
||||
}>;
|
||||
featuresText: string;
|
||||
primaryButtonLabel: string;
|
||||
secondaryButtonLabel: string;
|
||||
};
|
||||
|
||||
export type EditorTeamTemplateMessages = {
|
||||
members: Array<{
|
||||
name: string;
|
||||
role: string;
|
||||
bio: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type EditorTestimonialsTemplateMessages = {
|
||||
items: Array<{
|
||||
body: string;
|
||||
author: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type EditorBlogTemplateMessages = {
|
||||
posts: Array<{
|
||||
title: string;
|
||||
summary: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type EditorFooterTemplateMessages = {
|
||||
description: string;
|
||||
linksText: string;
|
||||
};
|
||||
|
||||
export type EditorTemplatesMessages = {
|
||||
hero: EditorHeroTemplateMessages;
|
||||
features: EditorFeaturesTemplateMessages;
|
||||
cta: EditorCtaTemplateMessages;
|
||||
faq: EditorFaqTemplateMessages;
|
||||
pricing: EditorPricingTemplateMessages;
|
||||
team: EditorTeamTemplateMessages;
|
||||
testimonials: EditorTestimonialsTemplateMessages;
|
||||
blog: EditorBlogTemplateMessages;
|
||||
footer: EditorFooterTemplateMessages;
|
||||
};
|
||||
|
||||
const EDITOR_TEMPLATES_MESSAGES: Record<AppLocale, EditorTemplatesMessages> = {
|
||||
en: {
|
||||
hero: {
|
||||
headline: "Your hero headline goes here",
|
||||
subheadline: "Describe your product or service in a single, clear sentence.",
|
||||
primaryButtonLabel: "Get started now",
|
||||
},
|
||||
features: {
|
||||
itemTitlePrefix: "Feature",
|
||||
itemTitleSuffix: "",
|
||||
itemDescription: "A short description of this feature.",
|
||||
},
|
||||
cta: {
|
||||
body:
|
||||
"Write a compelling CTA message here.\nDon't hesitate to get started!",
|
||||
buttonLabel: "Call to action",
|
||||
},
|
||||
faq: {
|
||||
title: "FAQ",
|
||||
subtitle: "Frequently asked questions",
|
||||
items: [
|
||||
{
|
||||
question: "How much does the service cost?",
|
||||
answer:
|
||||
"The core features are free, and premium features are available with a monthly subscription.",
|
||||
},
|
||||
{
|
||||
question: "What is your refund policy?",
|
||||
answer:
|
||||
"If there is no usage within 7 days after purchase, you can request a full refund.",
|
||||
},
|
||||
{
|
||||
question: "Can I invite teammates?",
|
||||
answer:
|
||||
"Yes, team invitations are available on Pro plans and above.",
|
||||
},
|
||||
],
|
||||
},
|
||||
pricing: {
|
||||
plans: [
|
||||
{ name: "Basic", price: "$9/month" },
|
||||
{ name: "Pro", price: "$29/month", popular: true },
|
||||
{ name: "Enterprise", price: "Contact us" },
|
||||
],
|
||||
featuresText: "• All core features\n• Email support\n• 1GB storage",
|
||||
primaryButtonLabel: "Start now",
|
||||
secondaryButtonLabel: "Choose plan",
|
||||
},
|
||||
team: {
|
||||
members: [
|
||||
{
|
||||
name: "Alex Kim",
|
||||
role: "Product Designer",
|
||||
bio: "Designs thoughtful user experiences.",
|
||||
},
|
||||
{
|
||||
name: "Jamie Lee",
|
||||
role: "Frontend Engineer",
|
||||
bio: "Builds clean, accessible UIs.",
|
||||
},
|
||||
{
|
||||
name: "Chris Park",
|
||||
role: "Backend Engineer",
|
||||
bio: "Keeps the infrastructure fast and reliable.",
|
||||
},
|
||||
],
|
||||
},
|
||||
testimonials: {
|
||||
items: [
|
||||
{
|
||||
body: "This builder dramatically reduced the time we spend creating landing pages.",
|
||||
author: "Alex Kim",
|
||||
},
|
||||
{
|
||||
body: "Even without strong design skills, we can still launch clean, modern pages.",
|
||||
author: "Jamie Lee",
|
||||
},
|
||||
{
|
||||
body: "Our whole team is happy with this builder.",
|
||||
author: "Chris Park",
|
||||
},
|
||||
],
|
||||
},
|
||||
blog: {
|
||||
posts: [
|
||||
{
|
||||
title: "Blog post 1",
|
||||
summary: "Write a short summary for your first post here.",
|
||||
},
|
||||
{
|
||||
title: "Blog post 2",
|
||||
summary: "Write a short summary for your second post here.",
|
||||
},
|
||||
{
|
||||
title: "Blog post 3",
|
||||
summary: "Write a short summary for your third post here.",
|
||||
},
|
||||
],
|
||||
},
|
||||
footer: {
|
||||
description: "The best choice for building better websites.",
|
||||
linksText: "Product\nPricing\nSupport\nContact",
|
||||
},
|
||||
},
|
||||
ko: {
|
||||
hero: {
|
||||
headline: "Hero 제목을 여기에 입력하세요",
|
||||
subheadline: "제품이나 서비스를 한 문장으로 설명하는 서브텍스트입니다.",
|
||||
primaryButtonLabel: "지금 시작하기",
|
||||
},
|
||||
features: {
|
||||
itemTitlePrefix: "Feature",
|
||||
itemTitleSuffix: " 제목",
|
||||
itemDescription: "해당 기능을 간단히 설명하는 텍스트입니다.",
|
||||
},
|
||||
cta: {
|
||||
body:
|
||||
"지금 바로 행동을 유도하는 CTA 텍스트를 입력하세요.\n망설이지 말고 시작하세요!",
|
||||
buttonLabel: "CTA 버튼",
|
||||
},
|
||||
faq: {
|
||||
title: "FAQ",
|
||||
subtitle: "자주 묻는 질문",
|
||||
items: [
|
||||
{
|
||||
question: "서비스 이용료는 얼마인가요?",
|
||||
answer: "기본 기능은 무료로 제공되며, 프리미엄 기능은 월 구독료가 발생합니다.",
|
||||
},
|
||||
{
|
||||
question: "환불 정책은 어떻게 되나요?",
|
||||
answer: "결제 후 7일 이내에 사용 이력이 없는 경우 전액 환불 가능합니다.",
|
||||
},
|
||||
{
|
||||
question: "팀원 초대 기능이 있나요?",
|
||||
answer: "네, 프로 요금제 이상부터 팀원 초대가 가능합니다.",
|
||||
},
|
||||
],
|
||||
},
|
||||
pricing: {
|
||||
plans: [
|
||||
{ name: "Basic", price: "₩9,900/월" },
|
||||
{ name: "Pro", price: "₩29,900/월", popular: true },
|
||||
{ name: "Enterprise", price: "문의" },
|
||||
],
|
||||
featuresText: "• 모든 기본 기능\n• 이메일 지원\n• 1GB 스토리지",
|
||||
primaryButtonLabel: "시작하기",
|
||||
secondaryButtonLabel: "선택하기",
|
||||
},
|
||||
team: {
|
||||
members: [
|
||||
{
|
||||
name: "홍길동",
|
||||
role: "Product Designer",
|
||||
bio: "사용자 경험을 설계합니다.",
|
||||
},
|
||||
{
|
||||
name: "김영희",
|
||||
role: "Frontend Engineer",
|
||||
bio: "깔끔한 UI를 구현합니다.",
|
||||
},
|
||||
{
|
||||
name: "이철수",
|
||||
role: "Backend Engineer",
|
||||
bio: "안정적인 인프라를 책임집니다.",
|
||||
},
|
||||
],
|
||||
},
|
||||
testimonials: {
|
||||
items: [
|
||||
{
|
||||
body: "이 서비스 덕분에 랜딩 페이지 제작 시간이 크게 줄었습니다.",
|
||||
author: "홍길동",
|
||||
},
|
||||
{
|
||||
body: "디자인을 잘 못해도 깔끔한 페이지를 만들 수 있어요.",
|
||||
author: "김영희",
|
||||
},
|
||||
{
|
||||
body: "팀 전체가 만족하는 빌더입니다.",
|
||||
author: "이철수",
|
||||
},
|
||||
],
|
||||
},
|
||||
blog: {
|
||||
posts: [
|
||||
{
|
||||
title: "블로그 포스트 1",
|
||||
summary: "첫 번째 포스트 요약을 여기에 입력하세요.",
|
||||
},
|
||||
{
|
||||
title: "블로그 포스트 2",
|
||||
summary: "두 번째 포스트 요약을 여기에 입력하세요.",
|
||||
},
|
||||
{
|
||||
title: "블로그 포스트 3",
|
||||
summary: "세 번째 포스트 요약을 여기에 입력하세요.",
|
||||
},
|
||||
],
|
||||
},
|
||||
footer: {
|
||||
description: "더 나은 웹사이트를 위한 최고의 선택.",
|
||||
linksText: "서비스 소개\n요금제\n고객지원\n문의하기",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorTemplatesMessages(
|
||||
locale: AppLocale | null | undefined,
|
||||
): EditorTemplatesMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_TEMPLATES_MESSAGES[key] ?? EDITOR_TEMPLATES_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorTextPanelMessages = {
|
||||
selectedTextLabel: string;
|
||||
selectedTextAria: string;
|
||||
alignLabel: string;
|
||||
alignAria: string;
|
||||
alignOptionLeft: string;
|
||||
alignOptionCenter: string;
|
||||
alignOptionRight: string;
|
||||
textStyleLabel: string;
|
||||
underlineLabel: string;
|
||||
strikeLabel: string;
|
||||
italicLabel: string;
|
||||
fontSizeLabel: string;
|
||||
fontSizeUnitLabel: string;
|
||||
letterSpacingLabel: string;
|
||||
letterSpacingPresetAria: string;
|
||||
letterSpacingSliderAria: string;
|
||||
letterSpacingInputAria: string;
|
||||
letterSpacingPresetTighter: string;
|
||||
letterSpacingPresetTight: string;
|
||||
letterSpacingPresetNormal: string;
|
||||
letterSpacingPresetWide: string;
|
||||
letterSpacingPresetWider: string;
|
||||
lineHeightLabel: string;
|
||||
lineHeightPresetTight: string;
|
||||
lineHeightPresetSnug: string;
|
||||
lineHeightPresetNormal: string;
|
||||
lineHeightPresetRelaxed: string;
|
||||
lineHeightPresetLoose: string;
|
||||
fontWeightLabel: string;
|
||||
fontWeightPresetNormal: string;
|
||||
fontWeightPresetMedium: string;
|
||||
fontWeightPresetSemibold: string;
|
||||
fontWeightPresetBold: string;
|
||||
textColorLabel: string;
|
||||
textColorPickerAria: string;
|
||||
textColorHexAria: string;
|
||||
backgroundColorLabel: string;
|
||||
backgroundColorPickerAria: string;
|
||||
backgroundColorHexAria: string;
|
||||
maxWidthLabel: string;
|
||||
maxWidthPresetAria: string;
|
||||
maxWidthSliderAria: string;
|
||||
maxWidthCustomAria: string;
|
||||
maxWidthPlaceholder: string;
|
||||
maxWidthPresetNone: string;
|
||||
maxWidthPresetProse: string;
|
||||
maxWidthPresetNarrow: string;
|
||||
};
|
||||
|
||||
const EDITOR_TEXT_PANEL_MESSAGES: Record<AppLocale, EditorTextPanelMessages> = {
|
||||
en: {
|
||||
selectedTextLabel: "Selected text block content",
|
||||
selectedTextAria: "Selected text block content",
|
||||
alignLabel: "Alignment",
|
||||
alignAria: "Alignment",
|
||||
alignOptionLeft: "Left",
|
||||
alignOptionCenter: "Center",
|
||||
alignOptionRight: "Right",
|
||||
textStyleLabel: "Text style",
|
||||
underlineLabel: "Underline",
|
||||
strikeLabel: "Strikethrough",
|
||||
italicLabel: "Italic",
|
||||
fontSizeLabel: "Font size",
|
||||
fontSizeUnitLabel: "(px)",
|
||||
letterSpacingLabel: "Letter spacing",
|
||||
letterSpacingPresetAria: "Letter spacing preset",
|
||||
letterSpacingSliderAria: "Letter spacing slider",
|
||||
letterSpacingInputAria: "Letter spacing custom (px)",
|
||||
letterSpacingPresetTighter: "Very tight",
|
||||
letterSpacingPresetTight: "Tight",
|
||||
letterSpacingPresetNormal: "Normal",
|
||||
letterSpacingPresetWide: "Wide",
|
||||
letterSpacingPresetWider: "Very wide",
|
||||
lineHeightLabel: "Line height",
|
||||
lineHeightPresetTight: "Tight",
|
||||
lineHeightPresetSnug: "Slightly tight",
|
||||
lineHeightPresetNormal: "Normal",
|
||||
lineHeightPresetRelaxed: "Relaxed",
|
||||
lineHeightPresetLoose: "Loose",
|
||||
fontWeightLabel: "Weight",
|
||||
fontWeightPresetNormal: "Regular",
|
||||
fontWeightPresetMedium: "Medium",
|
||||
fontWeightPresetSemibold: "Semibold",
|
||||
fontWeightPresetBold: "Bold",
|
||||
textColorLabel: "Text color",
|
||||
textColorPickerAria: "Text color picker",
|
||||
textColorHexAria: "Text color HEX",
|
||||
backgroundColorLabel: "Block background color",
|
||||
backgroundColorPickerAria: "Text block background color picker",
|
||||
backgroundColorHexAria: "Text block background color HEX",
|
||||
maxWidthLabel: "Max width",
|
||||
maxWidthPresetAria: "Max width preset",
|
||||
maxWidthSliderAria: "Max width slider (ch)",
|
||||
maxWidthCustomAria: "Max width custom",
|
||||
maxWidthPlaceholder: "e.g. 600px, 40rem, 80%, 60ch",
|
||||
maxWidthPresetNone: "No limit",
|
||||
maxWidthPresetProse: "Body width (60ch)",
|
||||
maxWidthPresetNarrow: "Narrow (40ch)",
|
||||
},
|
||||
ko: {
|
||||
selectedTextLabel: "선택한 텍스트 블록 내용",
|
||||
selectedTextAria: "선택한 텍스트 블록 내용",
|
||||
alignLabel: "정렬",
|
||||
alignAria: "정렬",
|
||||
alignOptionLeft: "왼쪽",
|
||||
alignOptionCenter: "가운데",
|
||||
alignOptionRight: "오른쪽",
|
||||
textStyleLabel: "텍스트 스타일",
|
||||
underlineLabel: "밑줄",
|
||||
strikeLabel: "가운데줄",
|
||||
italicLabel: "이탤릭",
|
||||
fontSizeLabel: "글자 크기",
|
||||
fontSizeUnitLabel: "(px)",
|
||||
letterSpacingLabel: "글자 간격",
|
||||
letterSpacingPresetAria: "글자 간격 프리셋",
|
||||
letterSpacingSliderAria: "글자 간격 슬라이더",
|
||||
letterSpacingInputAria: "글자 간격 커스텀 (px)",
|
||||
letterSpacingPresetTighter: "아주 좁게",
|
||||
letterSpacingPresetTight: "좁게",
|
||||
letterSpacingPresetNormal: "보통",
|
||||
letterSpacingPresetWide: "넓게",
|
||||
letterSpacingPresetWider: "아주 넓게",
|
||||
lineHeightLabel: "줄 간격",
|
||||
lineHeightPresetTight: "좁게",
|
||||
lineHeightPresetSnug: "약간 좁게",
|
||||
lineHeightPresetNormal: "보통",
|
||||
lineHeightPresetRelaxed: "넓게",
|
||||
lineHeightPresetLoose: "아주 넓게",
|
||||
fontWeightLabel: "굵기",
|
||||
fontWeightPresetNormal: "보통",
|
||||
fontWeightPresetMedium: "중간",
|
||||
fontWeightPresetSemibold: "세미볼드",
|
||||
fontWeightPresetBold: "볼드",
|
||||
textColorLabel: "텍스트 색상",
|
||||
textColorPickerAria: "텍스트 색상 피커",
|
||||
textColorHexAria: "텍스트 색상 HEX",
|
||||
backgroundColorLabel: "블록 배경색",
|
||||
backgroundColorPickerAria: "텍스트 블록 배경색 피커",
|
||||
backgroundColorHexAria: "텍스트 블록 배경색 HEX",
|
||||
maxWidthLabel: "최대 너비",
|
||||
maxWidthPresetAria: "최대 너비 프리셋",
|
||||
maxWidthSliderAria: "최대 너비 슬라이더 (ch 단위)",
|
||||
maxWidthCustomAria: "최대 너비 커스텀",
|
||||
maxWidthPlaceholder: "예: 600px, 40rem, 80%, 60ch",
|
||||
maxWidthPresetNone: "제한 없음",
|
||||
maxWidthPresetProse: "본문 폭 (60ch)",
|
||||
maxWidthPresetNarrow: "좁게 (40ch)",
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorTextPanelMessages(
|
||||
locale: AppLocale | null | undefined,
|
||||
): EditorTextPanelMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_TEXT_PANEL_MESSAGES[key] ?? EDITOR_TEXT_PANEL_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type EditorVideoPanelMessages = {
|
||||
sourceLabel: string;
|
||||
sourceAria: string;
|
||||
sourceOptionUrl: string;
|
||||
sourceOptionUpload: string;
|
||||
|
||||
urlLabel: string;
|
||||
urlAria: string;
|
||||
|
||||
titleLabel: string;
|
||||
titleAria: string;
|
||||
|
||||
ariaLabelLabel: string;
|
||||
ariaLabelAria: string;
|
||||
|
||||
captionTextLabel: string;
|
||||
captionTextAria: string;
|
||||
|
||||
posterImageUrlLabel: string;
|
||||
posterImageUrlAria: string;
|
||||
|
||||
uploadLabel: string;
|
||||
uploadAria: string;
|
||||
|
||||
styleSectionTitle: string;
|
||||
|
||||
cardBackgroundLabel: string;
|
||||
cardBackgroundPickerAria: string;
|
||||
cardBackgroundHexAria: string;
|
||||
|
||||
alignLabel: string;
|
||||
alignAria: string;
|
||||
alignOptionLeft: string;
|
||||
alignOptionCenter: string;
|
||||
alignOptionRight: string;
|
||||
|
||||
widthModeLabel: string;
|
||||
widthModeAria: string;
|
||||
widthModeOptionAuto: string;
|
||||
widthModeOptionFull: string;
|
||||
widthModeOptionFixed: string;
|
||||
|
||||
fixedWidthLabel: string;
|
||||
fixedWidthUnitLabel: string;
|
||||
fixedWidthPresetSmall: string;
|
||||
fixedWidthPresetMedium: string;
|
||||
fixedWidthPresetLarge: string;
|
||||
|
||||
cardPaddingLabel: string;
|
||||
cardPaddingUnitLabel: string;
|
||||
|
||||
cardBorderRadiusLabel: string;
|
||||
cardBorderRadiusUnitLabel: string;
|
||||
|
||||
startTimeLabel: string;
|
||||
startTimeUnitLabel: string;
|
||||
|
||||
endTimeLabel: string;
|
||||
endTimeUnitLabel: string;
|
||||
|
||||
aspectRatioLabel: string;
|
||||
aspectRatioAria: string;
|
||||
|
||||
autoplayLabel: string;
|
||||
loopLabel: string;
|
||||
mutedLabel: string;
|
||||
controlsLabel: string;
|
||||
};
|
||||
|
||||
const EDITOR_VIDEO_PANEL_MESSAGES: Record<AppLocale, EditorVideoPanelMessages> = {
|
||||
en: {
|
||||
sourceLabel: "Video source",
|
||||
sourceAria: "Video source",
|
||||
sourceOptionUrl: "URL",
|
||||
sourceOptionUpload: "File upload",
|
||||
|
||||
urlLabel: "Video URL",
|
||||
urlAria: "Video URL",
|
||||
|
||||
titleLabel: "Video title",
|
||||
titleAria: "Video title",
|
||||
|
||||
ariaLabelLabel: "Video aria-label",
|
||||
ariaLabelAria: "Video aria-label",
|
||||
|
||||
captionTextLabel: "Video caption text",
|
||||
captionTextAria: "Video caption text",
|
||||
|
||||
posterImageUrlLabel: "Poster image URL",
|
||||
posterImageUrlAria: "Poster image URL",
|
||||
|
||||
uploadLabel: "Video file upload",
|
||||
uploadAria: "Video file upload",
|
||||
|
||||
styleSectionTitle: "Video style",
|
||||
|
||||
cardBackgroundLabel: "Card background color",
|
||||
cardBackgroundPickerAria: "Video card background color picker",
|
||||
cardBackgroundHexAria: "Video card background color HEX",
|
||||
|
||||
alignLabel: "Video alignment",
|
||||
alignAria: "Video alignment",
|
||||
alignOptionLeft: "Left",
|
||||
alignOptionCenter: "Center",
|
||||
alignOptionRight: "Right",
|
||||
|
||||
widthModeLabel: "Video width mode",
|
||||
widthModeAria: "Video width mode",
|
||||
widthModeOptionAuto: "Fit to content",
|
||||
widthModeOptionFull: "Full width",
|
||||
widthModeOptionFixed: "Fixed width (px)",
|
||||
|
||||
fixedWidthLabel: "Fixed width (px)",
|
||||
fixedWidthUnitLabel: "(px)",
|
||||
fixedWidthPresetSmall: "Small",
|
||||
fixedWidthPresetMedium: "Medium",
|
||||
fixedWidthPresetLarge: "Wide",
|
||||
|
||||
cardPaddingLabel: "Card padding",
|
||||
cardPaddingUnitLabel: "(px)",
|
||||
|
||||
cardBorderRadiusLabel: "Card border radius",
|
||||
cardBorderRadiusUnitLabel: "(px)",
|
||||
|
||||
startTimeLabel: "Start time (sec)",
|
||||
startTimeUnitLabel: "(sec)",
|
||||
|
||||
endTimeLabel: "End time (sec)",
|
||||
endTimeUnitLabel: "(sec)",
|
||||
|
||||
aspectRatioLabel: "Video aspect ratio",
|
||||
aspectRatioAria: "Video aspect ratio",
|
||||
|
||||
autoplayLabel: "Autoplay",
|
||||
loopLabel: "Loop",
|
||||
mutedLabel: "Muted",
|
||||
controlsLabel: "Show controls",
|
||||
},
|
||||
ko: {
|
||||
sourceLabel: "비디오 소스",
|
||||
sourceAria: "비디오 소스",
|
||||
sourceOptionUrl: "URL",
|
||||
sourceOptionUpload: "파일 업로드",
|
||||
|
||||
urlLabel: "비디오 URL",
|
||||
urlAria: "비디오 URL",
|
||||
|
||||
titleLabel: "비디오 제목",
|
||||
titleAria: "비디오 제목",
|
||||
|
||||
ariaLabelLabel: "비디오 aria-label",
|
||||
ariaLabelAria: "비디오 aria-label",
|
||||
|
||||
captionTextLabel: "비디오 캡션 텍스트",
|
||||
captionTextAria: "비디오 캡션 텍스트",
|
||||
|
||||
posterImageUrlLabel: "포스터 이미지 URL",
|
||||
posterImageUrlAria: "포스터 이미지 URL",
|
||||
|
||||
uploadLabel: "비디오 파일 업로드",
|
||||
uploadAria: "비디오 파일 업로드",
|
||||
|
||||
styleSectionTitle: "비디오 스타일",
|
||||
|
||||
cardBackgroundLabel: "카드 배경색",
|
||||
cardBackgroundPickerAria: "비디오 카드 배경색 피커",
|
||||
cardBackgroundHexAria: "비디오 카드 배경색 HEX",
|
||||
|
||||
alignLabel: "비디오 정렬",
|
||||
alignAria: "비디오 정렬",
|
||||
alignOptionLeft: "왼쪽",
|
||||
alignOptionCenter: "가운데",
|
||||
alignOptionRight: "오른쪽",
|
||||
|
||||
widthModeLabel: "비디오 너비 모드",
|
||||
widthModeAria: "비디오 너비 모드",
|
||||
widthModeOptionAuto: "내용에 맞춤",
|
||||
widthModeOptionFull: "가로 전체",
|
||||
widthModeOptionFixed: "고정 너비 (px)",
|
||||
|
||||
fixedWidthLabel: "고정 너비 (px)",
|
||||
fixedWidthUnitLabel: "(px)",
|
||||
fixedWidthPresetSmall: "작게",
|
||||
fixedWidthPresetMedium: "보통",
|
||||
fixedWidthPresetLarge: "넓게",
|
||||
|
||||
cardPaddingLabel: "카드 패딩",
|
||||
cardPaddingUnitLabel: "(px)",
|
||||
|
||||
cardBorderRadiusLabel: "카드 모서리 둥글기",
|
||||
cardBorderRadiusUnitLabel: "(px)",
|
||||
|
||||
startTimeLabel: "시작 시점 (초)",
|
||||
startTimeUnitLabel: "(초)",
|
||||
|
||||
endTimeLabel: "종료 시점 (초)",
|
||||
endTimeUnitLabel: "(초)",
|
||||
|
||||
aspectRatioLabel: "화면 비율",
|
||||
aspectRatioAria: "화면 비율",
|
||||
|
||||
autoplayLabel: "자동 재생",
|
||||
loopLabel: "반복 재생",
|
||||
mutedLabel: "음소거",
|
||||
controlsLabel: "재생 컨트롤 표시",
|
||||
},
|
||||
};
|
||||
|
||||
export function getEditorVideoPanelMessages(locale: AppLocale | null | undefined): EditorVideoPanelMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return EDITOR_VIDEO_PANEL_MESSAGES[key] ?? EDITOR_VIDEO_PANEL_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type PreviewMessages = {
|
||||
headerTitle: string;
|
||||
headerDescription: string;
|
||||
exportZipButtonLabel: string;
|
||||
navProjects: string;
|
||||
navBackToEditor: string;
|
||||
};
|
||||
|
||||
const PREVIEW_MESSAGES: Record<AppLocale, PreviewMessages> = {
|
||||
en: {
|
||||
headerTitle: "Page Preview",
|
||||
headerDescription: "Preview of the page built with the visual editor.",
|
||||
exportZipButtonLabel: "Export as page files (ZIP)",
|
||||
navProjects: "Projects",
|
||||
navBackToEditor: "Back to editor",
|
||||
},
|
||||
ko: {
|
||||
headerTitle: "Page Preview",
|
||||
headerDescription: "빌더로 만든 페이지를 미리 보는 화면",
|
||||
exportZipButtonLabel: "페이지 파일로 내보내기 (ZIP)",
|
||||
navProjects: "프로젝트 목록",
|
||||
navBackToEditor: "에디터로 돌아가기",
|
||||
},
|
||||
};
|
||||
|
||||
export function getPreviewMessages(locale: AppLocale | null | undefined): PreviewMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return PREVIEW_MESSAGES[key] ?? PREVIEW_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type ProjectsMessages = {
|
||||
headerTitle: string;
|
||||
headerDescription: string;
|
||||
errorFetchUnauthorized: string;
|
||||
errorFetchGeneric: string;
|
||||
errorDeleteSingle: string;
|
||||
errorDeleteBulkAllFailed: string;
|
||||
errorDeleteBulkSomeFailed: string;
|
||||
confirmDeleteSingle: string;
|
||||
confirmDeleteBulk: string;
|
||||
emptyListMessage: string;
|
||||
toolbarSelectedPrefix: string;
|
||||
toolbarSelectedSuffix: string;
|
||||
toolbarDeleteSelected: string;
|
||||
toolbarCreateNew: string;
|
||||
tableHeaderTitle: string;
|
||||
tableHeaderSlug: string;
|
||||
tableHeaderStatus: string;
|
||||
tableHeaderCreatedAt: string;
|
||||
tableHeaderUpdatedAt: string;
|
||||
tableHeaderActions: string;
|
||||
tableHeaderSelectAllAria: string;
|
||||
tableRowSelectAriaSuffix: string;
|
||||
actionEdit: string;
|
||||
actionPreview: string;
|
||||
actionViewSubmissions: string;
|
||||
actionDelete: string;
|
||||
pagerTotalPrefix: string;
|
||||
pagerTotalCountSuffix: string;
|
||||
pagerPrevLabel: string;
|
||||
pagerNextLabel: string;
|
||||
};
|
||||
|
||||
const PROJECTS_MESSAGES: Record<AppLocale, ProjectsMessages> = {
|
||||
en: {
|
||||
headerTitle: "Projects",
|
||||
headerDescription: "See all saved projects at a glance.",
|
||||
errorFetchUnauthorized:
|
||||
"You need to be signed in to view your projects. Please log in again.",
|
||||
errorFetchGeneric:
|
||||
"An error occurred while loading your projects. Please try again later.",
|
||||
errorDeleteSingle:
|
||||
"An error occurred while deleting the project. Please try again later.",
|
||||
errorDeleteBulkAllFailed:
|
||||
"An error occurred while deleting the selected projects. Please try again later.",
|
||||
errorDeleteBulkSomeFailed:
|
||||
"Failed to delete some projects. Please refresh and review the list.",
|
||||
confirmDeleteSingle:
|
||||
"Delete this project? This cannot be undone and any local/auto-saved data will also be removed.",
|
||||
confirmDeleteBulk:
|
||||
"Delete all selected projects? This cannot be undone and any local/auto-saved data will also be removed.",
|
||||
emptyListMessage: "No projects saved yet. Save a project from the editor to see it here.",
|
||||
toolbarSelectedPrefix: "Selected projects: ",
|
||||
toolbarSelectedSuffix: "",
|
||||
toolbarDeleteSelected: "Delete selected",
|
||||
toolbarCreateNew: "Create new project",
|
||||
tableHeaderTitle: "Title",
|
||||
tableHeaderSlug: "Address (slug)",
|
||||
tableHeaderStatus: "Status",
|
||||
tableHeaderCreatedAt: "Created at",
|
||||
tableHeaderUpdatedAt: "Updated at",
|
||||
tableHeaderActions: "Actions",
|
||||
tableHeaderSelectAllAria: "Select all projects on current page",
|
||||
tableRowSelectAriaSuffix: " (select)",
|
||||
actionEdit: "Edit",
|
||||
actionPreview: "Preview",
|
||||
actionViewSubmissions: "Form submissions",
|
||||
actionDelete: "Delete",
|
||||
pagerTotalPrefix: "Total ",
|
||||
pagerTotalCountSuffix: " items, ",
|
||||
pagerPrevLabel: "Previous",
|
||||
pagerNextLabel: "Next",
|
||||
},
|
||||
ko: {
|
||||
headerTitle: "프로젝트 목록",
|
||||
headerDescription: "저장된 프로젝트들을 한 눈에 볼 수 있는 목록",
|
||||
errorFetchUnauthorized:
|
||||
"프로젝트 목록을 불러오는 중 인증 오류가 발생했습니다. 다시 로그인해 주세요.",
|
||||
errorFetchGeneric:
|
||||
"프로젝트 목록을 불러오는 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.",
|
||||
errorDeleteSingle:
|
||||
"프로젝트 삭제 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.",
|
||||
errorDeleteBulkAllFailed:
|
||||
"선택한 프로젝트를 삭제하는 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.",
|
||||
errorDeleteBulkSomeFailed:
|
||||
"일부 프로젝트 삭제에 실패했습니다. 페이지를 새로고침한 뒤 목록을 확인해 주세요.",
|
||||
confirmDeleteSingle:
|
||||
"이 프로젝트를 삭제할까요? 삭제 후에는 되돌릴 수 없습니다. (로컬 저장 및 자동저장 데이터도 함께 삭제됩니다.)",
|
||||
confirmDeleteBulk:
|
||||
"선택한 프로젝트를 모두 삭제할까요? 삭제 후에는 되돌릴 수 없습니다. (로컬 저장 및 자동저장 데이터도 함께 삭제됩니다.)",
|
||||
emptyListMessage:
|
||||
"아직 저장된 프로젝트가 없습니다. 에디터에서 프로젝트를 저장해 보세요.",
|
||||
toolbarSelectedPrefix: "선택된 프로젝트: ",
|
||||
toolbarSelectedSuffix: "개",
|
||||
toolbarDeleteSelected: "선택 삭제",
|
||||
toolbarCreateNew: "새 프로젝트 만들기",
|
||||
tableHeaderTitle: "제목",
|
||||
tableHeaderSlug: "주소(slug)",
|
||||
tableHeaderStatus: "상태",
|
||||
tableHeaderCreatedAt: "생성일",
|
||||
tableHeaderUpdatedAt: "수정일",
|
||||
tableHeaderActions: "액션",
|
||||
tableHeaderSelectAllAria: "전체 선택",
|
||||
tableRowSelectAriaSuffix: " 선택",
|
||||
actionEdit: "편집",
|
||||
actionPreview: "미리보기",
|
||||
actionViewSubmissions: "폼 제출 내역",
|
||||
actionDelete: "삭제",
|
||||
pagerTotalPrefix: "전체 ",
|
||||
pagerTotalCountSuffix: "개 중 ",
|
||||
pagerPrevLabel: "이전",
|
||||
pagerNextLabel: "다음",
|
||||
},
|
||||
};
|
||||
|
||||
export function getProjectsMessages(locale: AppLocale | null | undefined): ProjectsMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return PROJECTS_MESSAGES[key] ?? PROJECTS_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type PublicPageRendererMessages = {
|
||||
requiredFieldsPrefix: string;
|
||||
submitSuccessDefault: string;
|
||||
submitErrorDefault: string;
|
||||
|
||||
checkboxGroupLabelImageAltFallback: string;
|
||||
checkboxOptionImageAltFallback: string;
|
||||
radioOptionImageAltFallback: string;
|
||||
};
|
||||
|
||||
const PUBLIC_PAGE_RENDERER_MESSAGES: Record<AppLocale, PublicPageRendererMessages> = {
|
||||
en: {
|
||||
requiredFieldsPrefix: "Please fill in the following required fields:",
|
||||
submitSuccessDefault: "Submitted successfully.",
|
||||
submitErrorDefault: "An error occurred while submitting.",
|
||||
|
||||
checkboxGroupLabelImageAltFallback: "Form group title",
|
||||
checkboxOptionImageAltFallback: "Checkbox option",
|
||||
radioOptionImageAltFallback: "Radio option",
|
||||
},
|
||||
ko: {
|
||||
requiredFieldsPrefix: "다음 필수 항목을 입력해 주세요:",
|
||||
submitSuccessDefault: "성공적으로 전송되었습니다.",
|
||||
submitErrorDefault: "전송 중 오류가 발생했습니다.",
|
||||
|
||||
checkboxGroupLabelImageAltFallback: "폼 그룹 타이틀",
|
||||
checkboxOptionImageAltFallback: "체크박스 옵션",
|
||||
radioOptionImageAltFallback: "라디오 옵션",
|
||||
},
|
||||
};
|
||||
|
||||
export function getPublicPageRendererMessages(
|
||||
locale: AppLocale | null | undefined,
|
||||
): PublicPageRendererMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return PUBLIC_PAGE_RENDERER_MESSAGES[key] ?? PUBLIC_PAGE_RENDERER_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import type { AppLocale } from "../locale";
|
||||
import { DEFAULT_LOCALE } from "../locale";
|
||||
|
||||
export type SubmissionsMessages = {
|
||||
headerTitle: string;
|
||||
headerDescription: string;
|
||||
errorUnauthorized: string;
|
||||
errorGeneric: string;
|
||||
errorLogout: string;
|
||||
loadingText: string;
|
||||
emptyText: string;
|
||||
tableHeaderCreatedAt: string;
|
||||
tableHeaderProject: string;
|
||||
tableHeaderSlug: string;
|
||||
tableHeaderName: string;
|
||||
tableHeaderEmail: string;
|
||||
tableHeaderPhone: string;
|
||||
tableHeaderBirthdate: string;
|
||||
tableHeaderOtherFields: string;
|
||||
};
|
||||
|
||||
const SUBMISSIONS_MESSAGES: Record<AppLocale, SubmissionsMessages> = {
|
||||
en: {
|
||||
headerTitle: "All form submissions",
|
||||
headerDescription:
|
||||
"View form submissions across all projects for the current signed-in account.",
|
||||
errorUnauthorized:
|
||||
"You need to be signed in to view form submissions. Please log in again.",
|
||||
errorGeneric:
|
||||
"An error occurred while loading form submissions. Please try again later.",
|
||||
errorLogout:
|
||||
"An error occurred while logging out. Please try again later.",
|
||||
loadingText: "Loading form submissions...",
|
||||
emptyText: "No form submissions have been collected yet.",
|
||||
tableHeaderCreatedAt: "Submitted at",
|
||||
tableHeaderProject: "Project",
|
||||
tableHeaderSlug: "Slug",
|
||||
tableHeaderName: "Name",
|
||||
tableHeaderEmail: "Email",
|
||||
tableHeaderPhone: "Phone",
|
||||
tableHeaderBirthdate: "Birthdate",
|
||||
tableHeaderOtherFields: "Other fields",
|
||||
},
|
||||
ko: {
|
||||
headerTitle: "전체 폼 제출 내역",
|
||||
headerDescription:
|
||||
"로그인한 계정의 모든 프로젝트에 대한 폼 제출 데이터를 확인할 수 있습니다.",
|
||||
errorUnauthorized:
|
||||
"폼 제출 내역을 조회하려면 로그인이 필요합니다. 다시 로그인해 주세요.",
|
||||
errorGeneric:
|
||||
"폼 제출 내역을 불러오는 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.",
|
||||
errorLogout:
|
||||
"로그아웃 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.",
|
||||
loadingText: "폼 제출 내역을 불러오는 중입니다...",
|
||||
emptyText: "아직 수집된 폼 제출 내역이 없습니다.",
|
||||
tableHeaderCreatedAt: "제출 시각",
|
||||
tableHeaderProject: "프로젝트",
|
||||
tableHeaderSlug: "Slug",
|
||||
tableHeaderName: "이름",
|
||||
tableHeaderEmail: "이메일",
|
||||
tableHeaderPhone: "전화번호",
|
||||
tableHeaderBirthdate: "생년월일",
|
||||
tableHeaderOtherFields: "기타 필드",
|
||||
},
|
||||
};
|
||||
|
||||
export function getSubmissionsMessages(locale: AppLocale | null | undefined): SubmissionsMessages {
|
||||
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
|
||||
return SUBMISSIONS_MESSAGES[key] ?? SUBMISSIONS_MESSAGES[DEFAULT_LOCALE];
|
||||
}
|
||||
Reference in New Issue
Block a user