오류 수정
CI / test (push) Failing after 5m41s
CI / e2e (push) Has been skipped
CI / pr_and_merge (push) Has been skipped

This commit is contained in:
2025-12-12 18:04:31 +09:00
parent 6804665b95
commit 4840a530b6
205 changed files with 1802 additions and 9887 deletions
@@ -84,7 +84,7 @@ export function NumericPropertyControl({
<PropertySliderField
label=""
ariaLabelSlider={`${label} 슬라이더`}
ariaLabelInput={`${label} 커스텀${unitLabel ? ` ${unitLabel}` : ""}`}
ariaLabelInput={`${label} 커스텀`}
value={Number.isFinite(value) ? value : 0}
min={min}
max={max}
@@ -847,7 +847,7 @@ export function PublicPageRenderer({ blocks, projectSlug }: PublicPageRendererPr
: [
{
id: `${block.id}_item_1`,
text: "리스트 아이템 1",
text: "List item 1",
children: [],
},
];
+87 -63
View File
@@ -10,7 +10,8 @@ import { createFaqTemplateBlocks } from "@/app/editor/templates/faqTemplate";
import { createPricingTemplateBlocks } from "@/app/editor/templates/pricingTemplate";
import { createTestimonialsTemplateBlocks } from "@/app/editor/templates/testimonialsTemplate";
import { getEditorTemplatesMessages } from "@/features/i18n/messages/editorTemplates";
import { DEFAULT_LOCALE } from "@/features/i18n/locale";
import { getEditorBlockDefaultsMessages } from "@/features/i18n/messages/editorBlockDefaults";
import { DEFAULT_LOCALE, type AppLocale } from "@/features/i18n/locale";
// 블록 타입 정의: 텍스트/버튼/이미지/비디오/섹션/구분선/리스트/폼 블록/폼 요소 블록
export type BlockType =
@@ -739,27 +740,27 @@ export interface EditorState {
future: Block[][];
projectConfig: ProjectConfig;
updateProjectConfig: (partial: Partial<ProjectConfig>) => void;
addTextBlock: () => void;
addButtonBlock: () => void;
addTextBlock: (locale?: AppLocale | null) => void;
addButtonBlock: (locale?: AppLocale | null) => void;
addImageBlock: () => void;
addVideoBlock: () => void;
addDividerBlock: () => void;
addListBlock: () => void;
addListBlock: (locale?: AppLocale | null) => void;
addSectionBlock: () => void;
addFormBlock: () => void;
addFormInputBlock: () => void;
addFormSelectBlock: () => void;
addFormCheckboxBlock: () => void;
addFormRadioBlock: () => void;
addHeroTemplateSection: () => void;
addFeaturesTemplateSection: () => void;
addCtaTemplateSection: () => void;
addFaqTemplateSection: () => void;
addPricingTemplateSection: () => void;
addTestimonialsTemplateSection: () => void;
addBlogTemplateSection: () => void;
addTeamTemplateSection: () => void;
addFooterTemplateSection: () => void;
addFormBlock: (locale?: AppLocale | null) => void;
addFormInputBlock: (locale?: AppLocale | null) => void;
addFormSelectBlock: (locale?: AppLocale | null) => void;
addFormCheckboxBlock: (locale?: AppLocale | null) => void;
addFormRadioBlock: (locale?: AppLocale | null) => void;
addHeroTemplateSection: (locale?: AppLocale | null) => void;
addFeaturesTemplateSection: (locale?: AppLocale | null) => void;
addCtaTemplateSection: (locale?: AppLocale | null) => void;
addFaqTemplateSection: (locale?: AppLocale | null) => void;
addPricingTemplateSection: (locale?: AppLocale | null) => void;
addTestimonialsTemplateSection: (locale?: AppLocale | null) => void;
addBlogTemplateSection: (locale?: AppLocale | null) => void;
addTeamTemplateSection: (locale?: AppLocale | null) => void;
addFooterTemplateSection: (locale?: AppLocale | null) => void;
selectListItem: (itemId: string | null) => void;
indentSelectedListItem: (blockId: string) => void;
outdentSelectedListItem: (blockId: string) => void;
@@ -819,6 +820,8 @@ const getNextFormFieldName = (blocks: Block[], prefix: string): string => {
return `${prefix}-${max + 1}`;
};
const isKoLocale = (locale?: AppLocale | null): boolean => (locale ?? DEFAULT_LOCALE) === "ko";
// 에디터 스토어 생성 함수 (테스트 및 앱에서 공유 사용)
// set/get 은 zustand 내부 구현에 의해 주입되므로, 여기서는 any 로 완화해 사용한다.
const createEditorState = (set: any, get: any): EditorState => {
@@ -837,7 +840,7 @@ const createEditorState = (set: any, get: any): EditorState => {
history: [],
future: [],
projectConfig: {
title: "새 페이지",
title: "New page",
slug: "my-landing",
canvasPreset: "full",
canvasBgColorHex: "#020617",
@@ -862,7 +865,7 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// 텍스트 블록 추가: 기본 텍스트와 함께 생성 후 선택 상태로 만든다
addTextBlock: () => {
addTextBlock: (locale?: AppLocale | null) => {
const id = createId();
const { selectedBlockId, blocks } = get();
@@ -883,11 +886,12 @@ const createEditorState = (set: any, get: any): EditorState => {
}
}
const blockDefaults = getEditorBlockDefaultsMessages(locale);
const newBlock: Block = {
id,
type: "text",
props: {
text: "새 텍스트",
text: blockDefaults.text.defaultText,
align: "left",
size: "base",
},
@@ -903,7 +907,7 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// Hero 템플릿 섹션 추가: 섹션 1개와 기본 텍스트/버튼 블록들을 첫 컬럼에 배치한다
addHeroTemplateSection: () => {
addHeroTemplateSection: (locale?: AppLocale | null) => {
const { selectedBlockId, blocks } = get();
let sectionId = createId();
let replacingSectionId: string | null = null;
@@ -916,7 +920,7 @@ const createEditorState = (set: any, get: any): EditorState => {
}
}
const tpl = getEditorTemplatesMessages(DEFAULT_LOCALE);
const tpl = getEditorTemplatesMessages(locale);
const { blocks: templateBlocks, lastSelectedId } = createHeroTemplateBlocks({
sectionId,
createId,
@@ -942,7 +946,7 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// Features 템플릿 섹션 추가: 3컬럼(4/4/4) 섹션과 각 컬럼의 제목/설명 텍스트를 생성한다
addFeaturesTemplateSection: () => {
addFeaturesTemplateSection: (locale?: AppLocale | null) => {
const { selectedBlockId, blocks } = get();
let sectionId = createId();
let replacingSectionId: string | null = null;
@@ -955,7 +959,7 @@ const createEditorState = (set: any, get: any): EditorState => {
}
}
const tpl = getEditorTemplatesMessages(DEFAULT_LOCALE);
const tpl = getEditorTemplatesMessages(locale);
const { blocks: templateBlocks, lastSelectedId } = createFeaturesTemplateBlocks({
sectionId,
createId,
@@ -981,7 +985,7 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// Blog 템플릿 섹션 추가: 3컬럼 포스트 카드(제목/요약)를 생성한다
addBlogTemplateSection: () => {
addBlogTemplateSection: (locale?: AppLocale | null) => {
const { selectedBlockId, blocks } = get();
let sectionId = createId();
let replacingSectionId: string | null = null;
@@ -994,7 +998,7 @@ const createEditorState = (set: any, get: any): EditorState => {
}
}
const tpl = getEditorTemplatesMessages(DEFAULT_LOCALE);
const tpl = getEditorTemplatesMessages(locale);
const { blocks: templateBlocks, lastSelectedId } = createBlogTemplateBlocks({
sectionId,
createId,
@@ -1020,7 +1024,7 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// Team 템플릿 섹션 추가: 3컬럼 팀 카드(이름/역할/소개)를 생성한다
addTeamTemplateSection: () => {
addTeamTemplateSection: (locale?: AppLocale | null) => {
const { selectedBlockId, blocks } = get();
let sectionId = createId();
let replacingSectionId: string | null = null;
@@ -1033,7 +1037,7 @@ const createEditorState = (set: any, get: any): EditorState => {
}
}
const tpl = getEditorTemplatesMessages(DEFAULT_LOCALE);
const tpl = getEditorTemplatesMessages(locale);
const { blocks: templateBlocks, lastSelectedId } = createTeamTemplateBlocks({
sectionId,
createId,
@@ -1059,7 +1063,7 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// Footer 템플릿 섹션 추가: 링크/카피라이트 텍스트가 포함된 1컬럼 섹션을 생성한다
addFooterTemplateSection: () => {
addFooterTemplateSection: (locale?: AppLocale | null) => {
const { selectedBlockId, blocks } = get();
let sectionId = createId();
let replacingSectionId: string | null = null;
@@ -1072,7 +1076,7 @@ const createEditorState = (set: any, get: any): EditorState => {
}
}
const tpl = getEditorTemplatesMessages(DEFAULT_LOCALE);
const tpl = getEditorTemplatesMessages(locale);
const { blocks: templateBlocks, lastSelectedId } = createFooterTemplateBlocks({
sectionId,
createId,
@@ -1098,7 +1102,7 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// CTA 템플릿 섹션 추가: 텍스트와 버튼이 포함된 1컬럼 섹션을 생성한다
addCtaTemplateSection: () => {
addCtaTemplateSection: (locale?: AppLocale | null) => {
const { selectedBlockId, blocks } = get();
let sectionId = createId();
let replacingSectionId: string | null = null;
@@ -1111,7 +1115,7 @@ const createEditorState = (set: any, get: any): EditorState => {
}
}
const tpl = getEditorTemplatesMessages(DEFAULT_LOCALE);
const tpl = getEditorTemplatesMessages(locale);
const { blocks: templateBlocks, lastSelectedId } = createCtaTemplateBlocks({
sectionId,
createId,
@@ -1137,7 +1141,7 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// FAQ 템플릿 섹션 추가: 질문/답변 쌍이 수직으로 나열된 섹션을 생성한다
addFaqTemplateSection: () => {
addFaqTemplateSection: (locale?: AppLocale | null) => {
const { selectedBlockId, blocks } = get();
let sectionId = createId();
let replacingSectionId: string | null = null;
@@ -1150,7 +1154,7 @@ const createEditorState = (set: any, get: any): EditorState => {
}
}
const tpl = getEditorTemplatesMessages(DEFAULT_LOCALE);
const tpl = getEditorTemplatesMessages(locale);
const { blocks: templateBlocks, lastSelectedId } = createFaqTemplateBlocks({
sectionId,
createId,
@@ -1176,7 +1180,7 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// Pricing 템플릿 섹션 추가: 3컬럼 요금제 카드(플랜 이름/가격/설명)를 생성한다
addPricingTemplateSection: () => {
addPricingTemplateSection: (locale?: AppLocale | null) => {
const { selectedBlockId, blocks } = get();
let sectionId = createId();
let replacingSectionId: string | null = null;
@@ -1189,9 +1193,11 @@ const createEditorState = (set: any, get: any): EditorState => {
}
}
const tpl = getEditorTemplatesMessages(locale);
const { blocks: templateBlocks, lastSelectedId } = createPricingTemplateBlocks({
sectionId,
createId,
messages: tpl.pricing,
});
pushHistoryImpl(set, get);
@@ -1213,7 +1219,7 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// Testimonials 템플릿 섹션 추가: 3컬럼 후기 카드(본문/작성자)를 생성한다
addTestimonialsTemplateSection: () => {
addTestimonialsTemplateSection: (locale?: AppLocale | null) => {
const { selectedBlockId, blocks } = get();
let sectionId = createId();
let replacingSectionId: string | null = null;
@@ -1226,9 +1232,11 @@ const createEditorState = (set: any, get: any): EditorState => {
}
}
const tpl = getEditorTemplatesMessages(locale);
const { blocks: templateBlocks, lastSelectedId } = createTestimonialsTemplateBlocks({
sectionId,
createId,
messages: tpl.testimonials,
});
pushHistoryImpl(set, get);
@@ -1276,7 +1284,7 @@ const createEditorState = (set: any, get: any): EditorState => {
type: "image",
props: {
src: "",
alt: "이미지 설명",
alt: "Image description",
align: "center",
widthMode: "auto",
borderRadius: "md",
@@ -1340,11 +1348,12 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// 폼 입력 블록 추가: 루트에 기본 label/formFieldName 과 함께 생성 후 선택 상태로 만든다
addFormInputBlock: () => {
addFormInputBlock: (locale?: AppLocale | null) => {
const id = createId();
const { blocks } = get();
const label = "입력 필드";
const blockDefaults = getEditorBlockDefaultsMessages(locale);
const label = blockDefaults.formInput.label;
const formFieldName = getNextFormFieldName(blocks, "text");
const newBlock: Block = {
@@ -1380,15 +1389,17 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// 폼 셀렉트 블록 추가: 루트에 기본 label/formFieldName/options 와 함께 생성 후 선택 상태로 만든다
addFormSelectBlock: () => {
addFormSelectBlock: (locale?: AppLocale | null) => {
const id = createId();
const { blocks } = get();
const label = "선택 필드";
const blockDefaults = getEditorBlockDefaultsMessages(locale);
const selectDefaults = blockDefaults.formSelect;
const label = selectDefaults.label;
const formFieldName = getNextFormFieldName(blocks, "select");
const options: FormSelectOption[] = [
{ label: "옵션 1", value: "option_1" },
{ label: "옵션 2", value: "option_2" },
{ label: selectDefaults.option1Label, value: "option_1" },
{ label: selectDefaults.option2Label, value: "option_2" },
];
const newBlock: Block = {
@@ -1422,15 +1433,17 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// 폼 체크박스 블록 추가: 루트에 기본 groupLabel/formFieldName/options 와 함께 생성 후 선택 상태로 만든다
addFormCheckboxBlock: () => {
addFormCheckboxBlock: (locale?: AppLocale | null) => {
const id = createId();
const { blocks } = get();
const groupLabel = "체크박스";
const blockDefaults = getEditorBlockDefaultsMessages(locale);
const checkboxDefaults = blockDefaults.formCheckbox;
const groupLabel = checkboxDefaults.groupLabel;
const formFieldName = getNextFormFieldName(blocks, "checkbox");
const options: FormCheckboxOption[] = [
{ label: "체크 1", value: "check_1" },
{ label: "체크 2", value: "check_2" },
{ label: checkboxDefaults.option1Label, value: "check_1" },
{ label: checkboxDefaults.option2Label, value: "check_2" },
];
const newBlock: Block = {
@@ -1465,15 +1478,17 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// 폼 라디오 그룹 블록 추가: 루트에 기본 groupLabel/formFieldName/options 와 함께 생성 후 선택 상태로 만든다
addFormRadioBlock: () => {
addFormRadioBlock: (locale?: AppLocale | null) => {
const id = createId();
const { blocks } = get();
const groupLabel = "라디오 그룹";
const blockDefaults = getEditorBlockDefaultsMessages(locale);
const radioDefaults = blockDefaults.formRadio;
const groupLabel = radioDefaults.groupLabel;
const formFieldName = getNextFormFieldName(blocks, "radio");
const options: FormRadioOption[] = [
{ label: "옵션 A", value: "option_a" },
{ label: "옵션 B", value: "option_b" },
{ label: radioDefaults.optionALabel, value: "option_a" },
{ label: radioDefaults.optionBLabel, value: "option_b" },
];
const newBlock: Block = {
@@ -1549,7 +1564,7 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// 리스트 블록 추가: 기본 항목/정렬과 함께 생성 후 선택 상태로 만든다
addListBlock: () => {
addListBlock: (locale?: AppLocale | null) => {
const id = createId();
const { selectedBlockId, blocks } = get();
@@ -1570,15 +1585,18 @@ const createEditorState = (set: any, get: any): EditorState => {
}
}
const blockDefaults = getEditorBlockDefaultsMessages(locale);
const itemText = blockDefaults.list.firstItemText;
const newBlock: Block = {
id,
type: "list",
props: {
items: ["리스트 아이템 1"],
items: [itemText],
itemsTree: [
{
id: `${id}_item_1`,
text: "리스트 아이템 1",
text: itemText,
children: [],
},
],
@@ -1624,28 +1642,31 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// 폼 블록 추가: 기본 contact 폼 설정과 함께 생성 후 선택 상태로 만든다
addFormBlock: () => {
addFormBlock: (locale?: AppLocale | null) => {
const id = createId();
const blockDefaults = getEditorBlockDefaultsMessages(locale);
const formDefaults = blockDefaults.form;
const fields: FormFieldConfig[] = [
{
id: `${id}_field_name`,
name: "name",
label: "이름",
label: formDefaults.nameLabel,
type: "text",
required: true,
},
{
id: `${id}_field_email`,
name: "email",
label: "이메일",
label: formDefaults.emailLabel,
type: "email",
required: true,
},
{
id: `${id}_field_message`,
name: "message",
label: "메시지",
label: formDefaults.messageLabel,
type: "textarea",
required: true,
},
@@ -1657,8 +1678,8 @@ const createEditorState = (set: any, get: any): EditorState => {
props: {
kind: "contact",
submitTarget: "internal",
successMessage: "성공적으로 전송되었습니다.",
errorMessage: "전송 중 오류가 발생했습니다.",
successMessage: formDefaults.successMessage,
errorMessage: formDefaults.errorMessage,
fields,
fieldIds: [],
submitButtonId: null,
@@ -1675,7 +1696,7 @@ const createEditorState = (set: any, get: any): EditorState => {
},
// 버튼 블록 추가: 기본 라벨/링크와 함께 생성 후 선택 상태로 만든다
addButtonBlock: () => {
addButtonBlock: (locale?: AppLocale | null) => {
const id = createId();
const { selectedBlockId, blocks } = get();
@@ -1695,11 +1716,14 @@ const createEditorState = (set: any, get: any): EditorState => {
}
}
}
const blockDefaults = getEditorBlockDefaultsMessages(locale);
const newBlock: Block = {
id,
type: "button",
props: {
label: "버튼",
label: blockDefaults.button.label,
href: "#",
align: "left",
size: "md",
+7
View File
@@ -10,6 +10,13 @@ export function LocaleSwitcher() {
const handleToggle = () => {
const nextLocale: AppLocale = locale === "en" ? "ko" : "en";
setLocale(nextLocale);
try {
const maxAgeSeconds = 60 * 60 * 24 * 365; // 1 year
document.cookie = `pb-locale=${nextLocale}; path=/; max-age=${maxAgeSeconds}`;
} catch {
// 쿠키 저장 실패는 무시 (로케일 상태는 여전히 컨텍스트에서 유지된다)
}
};
const labelText = locale === "en" ? "EN" : "KO";
+11
View File
@@ -46,6 +46,9 @@ export type EditorMessages = {
listItemToolbarMoveDownLabel: string;
listItemToolbarIndentLabel: string;
listItemToolbarOutdentLabel: string;
imageBlockEmptyPreviewPlaceholder: string;
columnAreaLabel: string;
};
const EDITOR_MESSAGES: Record<AppLocale, EditorMessages> = {
@@ -96,6 +99,10 @@ const EDITOR_MESSAGES: Record<AppLocale, EditorMessages> = {
listItemToolbarMoveDownLabel: "Move item down",
listItemToolbarIndentLabel: "Indent item",
listItemToolbarOutdentLabel: "Outdent item",
imageBlockEmptyPreviewPlaceholder:
"Enter an image URL or upload a file to see the preview here.",
columnAreaLabel: "Column area",
},
ko: {
headerTitle: "페이지 에디터",
@@ -144,6 +151,10 @@ const EDITOR_MESSAGES: Record<AppLocale, EditorMessages> = {
listItemToolbarMoveDownLabel: "아이템 아래로 이동",
listItemToolbarIndentLabel: "아이템 들여쓰기",
listItemToolbarOutdentLabel: "아이템 내어쓰기",
imageBlockEmptyPreviewPlaceholder:
"이미지 URL 을 입력하거나 파일을 업로드하면 여기에서 미리보기가 표시됩니다.",
columnAreaLabel: "컬럼 영역",
},
};
@@ -0,0 +1,121 @@
import type { AppLocale } from "../locale";
import { DEFAULT_LOCALE } from "../locale";
export type EditorBlockDefaultsMessages = {
text: {
defaultText: string;
};
list: {
firstItemText: string;
};
button: {
label: string;
};
form: {
nameLabel: string;
emailLabel: string;
messageLabel: string;
successMessage: string;
errorMessage: string;
};
formInput: {
label: string;
};
formSelect: {
label: string;
option1Label: string;
option2Label: string;
};
formCheckbox: {
groupLabel: string;
option1Label: string;
option2Label: string;
};
formRadio: {
groupLabel: string;
optionALabel: string;
optionBLabel: string;
};
};
const EDITOR_BLOCK_DEFAULTS_MESSAGES: Record<AppLocale, EditorBlockDefaultsMessages> = {
en: {
text: {
defaultText: "New text",
},
list: {
firstItemText: "List item 1",
},
button: {
label: "Button",
},
form: {
nameLabel: "Name",
emailLabel: "Email",
messageLabel: "Message",
successMessage: "Your message has been sent successfully.",
errorMessage: "An error occurred while submitting.",
},
formInput: {
label: "Input field",
},
formSelect: {
label: "Select field",
option1Label: "Option 1",
option2Label: "Option 2",
},
formCheckbox: {
groupLabel: "Checkbox group",
option1Label: "Check 1",
option2Label: "Check 2",
},
formRadio: {
groupLabel: "Radio group",
optionALabel: "Option A",
optionBLabel: "Option B",
},
},
ko: {
text: {
defaultText: "새 텍스트",
},
list: {
firstItemText: "리스트 아이템 1",
},
button: {
label: "버튼",
},
form: {
nameLabel: "이름",
emailLabel: "이메일",
messageLabel: "메시지",
successMessage: "성공적으로 전송되었습니다.",
errorMessage: "전송 중 오류가 발생했습니다.",
},
formInput: {
label: "입력 필드",
},
formSelect: {
label: "셀렉트 필드",
option1Label: "옵션 1",
option2Label: "옵션 2",
},
formCheckbox: {
groupLabel: "체크박스 그룹",
option1Label: "옵션 1",
option2Label: "옵션 2",
},
formRadio: {
groupLabel: "라디오 그룹",
optionALabel: "옵션 A",
optionBLabel: "옵션 B",
},
},
};
export function getEditorBlockDefaultsMessages(
locale: AppLocale | null | undefined,
): EditorBlockDefaultsMessages {
const key = (locale ?? DEFAULT_LOCALE) as AppLocale;
return EDITOR_BLOCK_DEFAULTS_MESSAGES[key] ?? EDITOR_BLOCK_DEFAULTS_MESSAGES[DEFAULT_LOCALE];
}
@@ -120,8 +120,8 @@ const EDITOR_BUTTON_PANEL_MESSAGES: Record<AppLocale, EditorButtonPanelMessages>
imagePlacementOptionTop: "Text top",
imagePlacementOptionBottom: "Text bottom",
paddingXLabel: "Horizontal padding (px)",
paddingYLabel: "Vertical padding (px)",
paddingXLabel: "Horizontal padding",
paddingYLabel: "Vertical padding",
linkLabel: "Button link",
linkAria: "Button link",
@@ -211,8 +211,8 @@ const EDITOR_BUTTON_PANEL_MESSAGES: Record<AppLocale, EditorButtonPanelMessages>
imagePlacementOptionTop: "텍스트 위쪽",
imagePlacementOptionBottom: "텍스트 아래쪽",
paddingXLabel: "가로 패딩 (px)",
paddingYLabel: "세로 패딩 (px)",
paddingXLabel: "가로 패딩",
paddingYLabel: "세로 패딩",
linkLabel: "버튼 링크",
linkAria: "버튼 링크",
@@ -57,9 +57,9 @@ const EDITOR_DIVIDER_PROPERTIES_PANEL_MESSAGES: Record<AppLocale, EditorDividerP
lengthModeAria: "Divider length mode",
lengthModeOptionAuto: "Fit content",
lengthModeOptionFull: "Full width",
lengthModeOptionFixed: "Fixed length (px)",
lengthModeOptionFixed: "Fixed length",
fixedLengthLabel: "Fixed length (px)",
fixedLengthLabel: "Fixed length",
fixedLengthUnitLabel: "(px)",
fixedLengthPresetShort: "Short",
fixedLengthPresetNormal: "Normal",
@@ -94,9 +94,9 @@ const EDITOR_DIVIDER_PROPERTIES_PANEL_MESSAGES: Record<AppLocale, EditorDividerP
lengthModeAria: "구분선 길이 모드",
lengthModeOptionAuto: "내용에 맞춤",
lengthModeOptionFull: "전체 폭",
lengthModeOptionFixed: "고정 길이 (px)",
lengthModeOptionFixed: "고정 길이",
fixedLengthLabel: "고정 길이 (px)",
fixedLengthLabel: "고정 길이",
fixedLengthUnitLabel: "(px)",
fixedLengthPresetShort: "짧게",
fixedLengthPresetNormal: "보통",
@@ -117,7 +117,7 @@ const EDITOR_FORM_CHECKBOX_PANEL_MESSAGES: Record<AppLocale, EditorFormCheckboxP
optionLayoutOptionStacked: "Vertical (default)",
optionLayoutOptionInline: "Horizontal (inline)",
labelGapLabel: "Label/field gap (px)",
labelGapLabel: "Label/field gap",
groupTitleLabel: "Group title",
@@ -148,13 +148,13 @@ const EDITOR_FORM_CHECKBOX_PANEL_MESSAGES: Record<AppLocale, EditorFormCheckboxP
styleSectionTitle: "Field style",
textSizeLabel: "Checkbox text size (px)",
textSizeLabel: "Checkbox text size",
textSizeUnitLabel: "(px)",
lineHeightLabel: "Checkbox line height (px)",
lineHeightLabel: "Checkbox line height",
lineHeightUnitLabel: "(px)",
letterSpacingLabel: "Checkbox letter spacing (px)",
letterSpacingLabel: "Checkbox letter spacing",
letterSpacingUnitLabel: "(px)",
widthModeLabel: "Field width",
@@ -165,13 +165,13 @@ const EDITOR_FORM_CHECKBOX_PANEL_MESSAGES: Record<AppLocale, EditorFormCheckboxP
fixedWidthLabel: "Field fixed width",
fixedWidthUnitLabel: "(px)",
paddingXLabel: "Checkbox horizontal padding (px)",
paddingXLabel: "Checkbox horizontal padding",
paddingXUnitLabel: "(px)",
paddingYLabel: "Checkbox vertical padding (px)",
paddingYLabel: "Checkbox vertical padding",
paddingYUnitLabel: "(px)",
optionGapLabel: "Checkbox option gap (px)",
optionGapLabel: "Checkbox option gap",
optionGapUnitLabel: "(px)",
textColorLabel: "Text color",
@@ -212,7 +212,7 @@ const EDITOR_FORM_CHECKBOX_PANEL_MESSAGES: Record<AppLocale, EditorFormCheckboxP
optionLayoutOptionStacked: "세로 (기본)",
optionLayoutOptionInline: "가로 (인라인)",
labelGapLabel: "라벨/필드 간격 (px)",
labelGapLabel: "라벨/필드 간격",
groupTitleLabel: "그룹 타이틀",
@@ -243,13 +243,13 @@ const EDITOR_FORM_CHECKBOX_PANEL_MESSAGES: Record<AppLocale, EditorFormCheckboxP
styleSectionTitle: "필드 스타일",
textSizeLabel: "체크박스 텍스트 크기 (px)",
textSizeLabel: "체크박스 텍스트 크기",
textSizeUnitLabel: "(px)",
lineHeightLabel: "체크박스 줄간격 (px)",
lineHeightLabel: "체크박스 줄간격",
lineHeightUnitLabel: "(px)",
letterSpacingLabel: "체크박스 자간 (px)",
letterSpacingLabel: "체크박스 자간",
letterSpacingUnitLabel: "(px)",
widthModeLabel: "필드 너비",
@@ -260,13 +260,13 @@ const EDITOR_FORM_CHECKBOX_PANEL_MESSAGES: Record<AppLocale, EditorFormCheckboxP
fixedWidthLabel: "필드 고정 너비",
fixedWidthUnitLabel: "(px)",
paddingXLabel: "체크박스 가로 패딩 (px)",
paddingXLabel: "체크박스 가로 패딩",
paddingXUnitLabel: "(px)",
paddingYLabel: "체크박스 세로 패딩 (px)",
paddingYLabel: "체크박스 세로 패딩",
paddingYUnitLabel: "(px)",
optionGapLabel: "체크박스 옵션 간격 (px)",
optionGapLabel: "체크박스 옵션 간격",
optionGapUnitLabel: "(px)",
textColorLabel: "텍스트 색상",
@@ -32,6 +32,10 @@ export type EditorFormControllerPanelMessages = {
formFixedWidthLabel: string;
formFixedWidthPresetNarrow: string;
formFixedWidthPresetNormal: string;
formFixedWidthPresetWide: string;
marginYLabel: string;
marginYPresetNone: string;
marginYPresetCompact: string;
@@ -52,6 +56,8 @@ export type EditorFormControllerPanelMessages = {
submitButtonLabel: string;
submitButtonAriaLabel: string;
submitButtonNoneOptionLabel: string;
sheetsGuideButtonLabel: string;
sheetsGuideHeading: string;
sheetsGuideCloseAriaLabel: string;
@@ -94,9 +100,13 @@ const EDITOR_FORM_CONTROLLER_PANEL_MESSAGES: Record<AppLocale, EditorFormControl
formWidthModeOptionFull: "Full width",
formWidthModeOptionFixed: "Fixed value",
formFixedWidthLabel: "Form fixed width (px)",
formFixedWidthLabel: "Form fixed width",
marginYLabel: "Form top/bottom margin (px)",
formFixedWidthPresetNarrow: "Narrow",
formFixedWidthPresetNormal: "Normal",
formFixedWidthPresetWide: "Wide",
marginYLabel: "Form top/bottom margin",
marginYPresetNone: "None",
marginYPresetCompact: "Compact",
marginYPresetNormal: "Normal",
@@ -116,6 +126,8 @@ const EDITOR_FORM_CONTROLLER_PANEL_MESSAGES: Record<AppLocale, EditorFormControl
submitButtonLabel: "Submit button",
submitButtonAriaLabel: "Submit button",
submitButtonNoneOptionLabel: "(None)",
sheetsGuideButtonLabel: "Google Sheets integration guide",
sheetsGuideHeading: "Google Sheets integration guide",
sheetsGuideCloseAriaLabel: "Close Google Sheets integration guide",
@@ -160,9 +172,13 @@ const EDITOR_FORM_CONTROLLER_PANEL_MESSAGES: Record<AppLocale, EditorFormControl
formWidthModeOptionFull: "전체 폭",
formWidthModeOptionFixed: "고정 값",
formFixedWidthLabel: "폼 고정 너비 (px)",
formFixedWidthLabel: "폼 고정 너비",
marginYLabel: "폼 위/아래 여백 (px)",
formFixedWidthPresetNarrow: "좁게",
formFixedWidthPresetNormal: "보통",
formFixedWidthPresetWide: "넓게",
marginYLabel: "폼 위/아래 여백",
marginYPresetNone: "없음",
marginYPresetCompact: "좁게",
marginYPresetNormal: "보통",
@@ -182,6 +198,8 @@ const EDITOR_FORM_CONTROLLER_PANEL_MESSAGES: Record<AppLocale, EditorFormControl
submitButtonLabel: "Submit 버튼",
submitButtonAriaLabel: "Submit 버튼",
submitButtonNoneOptionLabel: "선택 안 함",
sheetsGuideButtonLabel: "Google Sheets 연동 가이드",
sheetsGuideHeading: "Google Sheets 연동 가이드",
sheetsGuideCloseAriaLabel: "Google Sheets 연동 가이드 닫기",
@@ -22,6 +22,12 @@ export type EditorFormInputPanelMessages = {
labelGapLabel: string;
labelGapUnitLabel: string;
// Presets for label gap
labelGapPresetTight: string;
labelGapPresetNormal: string;
labelGapPresetRelaxed: string;
labelGapPresetExtra: string;
labelImageUrlLabel: string;
labelImageAltLabel: string;
@@ -44,9 +50,19 @@ export type EditorFormInputPanelMessages = {
lineHeightLabel: string;
lineHeightUnitLabel: string;
// Presets for line height
lineHeightPresetTight: string;
lineHeightPresetNormal: string;
lineHeightPresetLoose: string;
letterSpacingLabel: string;
letterSpacingUnitLabel: string;
// Presets for letter spacing
letterSpacingPresetTight: string;
letterSpacingPresetNormal: string;
letterSpacingPresetWide: string;
textAlignLabel: string;
textAlignOptionLeft: string;
textAlignOptionCenter: string;
@@ -61,12 +77,31 @@ export type EditorFormInputPanelMessages = {
fixedWidthLabel: string;
fixedWidthUnitLabel: string;
// Presets for fixed width
fixedWidthPresetSmall: string;
fixedWidthPresetMedium: string;
fixedWidthPresetLarge: string;
paddingXLabel: string;
paddingXUnitLabel: string;
// Presets for horizontal padding
paddingXPresetXs: string;
paddingXPresetSm: string;
paddingXPresetMd: string;
paddingXPresetLg: string;
paddingXPresetXl: string;
paddingYLabel: string;
paddingYUnitLabel: string;
// Presets for vertical padding
paddingYPresetXs: string;
paddingYPresetSm: string;
paddingYPresetMd: string;
paddingYPresetLg: string;
paddingYPresetXl: string;
textColorLabel: string;
textColorPickerAria: string;
textColorHexAria: string;
@@ -106,9 +141,14 @@ const EDITOR_FORM_INPUT_PANEL_MESSAGES: Record<AppLocale, EditorFormInputPanelMe
layoutLabel: "Layout",
layoutOptionStacked: "Vertical (default)",
layoutOptionInline: "Horizontal (inline)",
labelGapLabel: "Label/field gap (px)",
labelGapLabel: "Label/field gap",
labelGapUnitLabel: "(px)",
labelGapPresetTight: "Tight",
labelGapPresetNormal: "Normal",
labelGapPresetRelaxed: "Relaxed",
labelGapPresetExtra: "Extra",
labelImageUrlLabel: "Label image URL",
labelImageAltLabel: "Label image alt text",
@@ -125,15 +165,23 @@ const EDITOR_FORM_INPUT_PANEL_MESSAGES: Record<AppLocale, EditorFormInputPanelMe
requiredNoticeText: "Required state is configured in the form controller.",
textSizeLabel: "Field text size (px)",
textSizeLabel: "Field text size",
textSizeUnitLabel: "(px)",
lineHeightLabel: "Field line height (px)",
lineHeightLabel: "Field line height",
lineHeightUnitLabel: "(px)",
letterSpacingLabel: "Field letter spacing (px)",
lineHeightPresetTight: "Tight",
lineHeightPresetNormal: "Normal",
lineHeightPresetLoose: "Loose",
letterSpacingLabel: "Field letter spacing",
letterSpacingUnitLabel: "(px)",
letterSpacingPresetTight: "Tight",
letterSpacingPresetNormal: "Normal",
letterSpacingPresetWide: "Wide",
textAlignLabel: "Text alignment",
textAlignOptionLeft: "Left",
textAlignOptionCenter: "Center",
@@ -148,12 +196,28 @@ const EDITOR_FORM_INPUT_PANEL_MESSAGES: Record<AppLocale, EditorFormInputPanelMe
fixedWidthLabel: "Field fixed width",
fixedWidthUnitLabel: "(px)",
paddingXLabel: "Field horizontal padding (px)",
fixedWidthPresetSmall: "Small",
fixedWidthPresetMedium: "Medium",
fixedWidthPresetLarge: "Large",
paddingXLabel: "Field horizontal padding",
paddingXUnitLabel: "(px)",
paddingYLabel: "Field vertical padding (px)",
paddingXPresetXs: "Extra thin",
paddingXPresetSm: "Thin",
paddingXPresetMd: "Normal",
paddingXPresetLg: "Wide",
paddingXPresetXl: "Extra wide",
paddingYLabel: "Field vertical padding",
paddingYUnitLabel: "(px)",
paddingYPresetXs: "Extra thin",
paddingYPresetSm: "Thin",
paddingYPresetMd: "Normal",
paddingYPresetLg: "Wide",
paddingYPresetXl: "Extra wide",
textColorLabel: "Field text color",
textColorPickerAria: "Field text color picker",
textColorHexAria: "Field text color HEX",
@@ -191,9 +255,14 @@ const EDITOR_FORM_INPUT_PANEL_MESSAGES: Record<AppLocale, EditorFormInputPanelMe
layoutLabel: "레이아웃",
layoutOptionStacked: "세로 (기본)",
layoutOptionInline: "가로 (인라인)",
labelGapLabel: "라벨/필드 간격 (px)",
labelGapLabel: "라벨/필드 간격",
labelGapUnitLabel: "(px)",
labelGapPresetTight: "타이트",
labelGapPresetNormal: "보통",
labelGapPresetRelaxed: "느슨",
labelGapPresetExtra: "넓게",
labelImageUrlLabel: "라벨 이미지 URL",
labelImageAltLabel: "라벨 이미지 대체 텍스트",
@@ -210,15 +279,23 @@ const EDITOR_FORM_INPUT_PANEL_MESSAGES: Record<AppLocale, EditorFormInputPanelMe
requiredNoticeText: "필수 여부는 폼 컨트롤러에서 설정합니다.",
textSizeLabel: "필드 텍스트 크기 (px)",
textSizeLabel: "필드 텍스트 크기",
textSizeUnitLabel: "(px)",
lineHeightLabel: "필드 줄간격 (px)",
lineHeightLabel: "필드 줄간격",
lineHeightUnitLabel: "(px)",
letterSpacingLabel: "필드 자간 (px)",
lineHeightPresetTight: "타이트",
lineHeightPresetNormal: "보통",
lineHeightPresetLoose: "루즈",
letterSpacingLabel: "필드 자간",
letterSpacingUnitLabel: "(px)",
letterSpacingPresetTight: "좁게",
letterSpacingPresetNormal: "보통",
letterSpacingPresetWide: "넓게",
textAlignLabel: "텍스트 정렬",
textAlignOptionLeft: "왼쪽",
textAlignOptionCenter: "가운데",
@@ -233,12 +310,28 @@ const EDITOR_FORM_INPUT_PANEL_MESSAGES: Record<AppLocale, EditorFormInputPanelMe
fixedWidthLabel: "필드 고정 너비",
fixedWidthUnitLabel: "(px)",
paddingXLabel: "필드 가로 패딩 (px)",
fixedWidthPresetSmall: "작게",
fixedWidthPresetMedium: "보통",
fixedWidthPresetLarge: "넓게",
paddingXLabel: "필드 가로 패딩",
paddingXUnitLabel: "(px)",
paddingYLabel: "필드 세로 패딩 (px)",
paddingXPresetXs: "아주 얇게",
paddingXPresetSm: "얇게",
paddingXPresetMd: "보통",
paddingXPresetLg: "넓게",
paddingXPresetXl: "아주 넓게",
paddingYLabel: "필드 세로 패딩",
paddingYUnitLabel: "(px)",
paddingYPresetXs: "아주 얇게",
paddingYPresetSm: "얇게",
paddingYPresetMd: "보통",
paddingYPresetLg: "넓게",
paddingYPresetXl: "아주 넓게",
textColorLabel: "필드 텍스트 색상",
textColorPickerAria: "필드 텍스트 색상 피커",
textColorHexAria: "필드 텍스트 색상 HEX",
@@ -4,6 +4,50 @@ import { DEFAULT_LOCALE } from "../locale";
export type EditorFormRadioPanelMessages = {
sectionTitle: string;
// Group title & option configuration
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;
@@ -53,29 +97,72 @@ const EDITOR_FORM_RADIO_PANEL_MESSAGES: Record<AppLocale, EditorFormRadioPanelMe
en: {
sectionTitle: "Radio field",
groupTitleTypeLabel: "Group title type",
groupTitleTypeOptionText: "Text",
groupTitleTypeOptionImage: "Image",
groupTitleDisplayLabel: "Group title display mode",
groupTitleDisplayOptionVisible: "Visible (default)",
groupTitleDisplayOptionHidden: "Hidden",
layoutLabel: "Group title layout",
layoutOptionStacked: "Vertical (default)",
layoutOptionInline: "Horizontal (inline)",
optionLayoutLabel: "Option layout",
optionLayoutOptionStacked: "Vertical (default)",
optionLayoutOptionInline: "Horizontal (inline)",
labelGapLabel: "Label/field gap",
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: "Radio text size (px)",
textSizeLabel: "Radio text size",
textSizeUnitLabel: "(px)",
lineHeightLabel: "Radio line height (px)",
lineHeightLabel: "Radio line height",
lineHeightUnitLabel: "(px)",
letterSpacingLabel: "Radio letter spacing (px)",
letterSpacingLabel: "Radio letter spacing",
letterSpacingUnitLabel: "(px)",
fixedWidthLabel: "Field fixed width",
fixedWidthUnitLabel: "(px)",
paddingXLabel: "Radio horizontal padding (px)",
paddingXLabel: "Radio horizontal padding",
paddingXUnitLabel: "(px)",
paddingYLabel: "Radio vertical padding (px)",
paddingYLabel: "Radio vertical padding",
paddingYUnitLabel: "(px)",
optionGapLabel: "Radio option gap (px)",
optionGapLabel: "Radio option gap",
optionGapUnitLabel: "(px)",
textColorLabel: "Text color",
@@ -100,29 +187,72 @@ const EDITOR_FORM_RADIO_PANEL_MESSAGES: Record<AppLocale, EditorFormRadioPanelMe
ko: {
sectionTitle: "라디오 필드",
groupTitleTypeLabel: "그룹 타이틀 타입",
groupTitleTypeOptionText: "텍스트",
groupTitleTypeOptionImage: "이미지",
groupTitleDisplayLabel: "그룹 타이틀 표시 방식",
groupTitleDisplayOptionVisible: "표시 (기본)",
groupTitleDisplayOptionHidden: "숨김",
layoutLabel: "그룹 타이틀 레이아웃",
layoutOptionStacked: "세로 (기본)",
layoutOptionInline: "가로 (인라인)",
optionLayoutLabel: "옵션 레이아웃",
optionLayoutOptionStacked: "세로 (기본)",
optionLayoutOptionInline: "가로 (인라인)",
labelGapLabel: "라벨/필드 간격",
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)",
textSizeLabel: "라디오 텍스트 크기",
textSizeUnitLabel: "(px)",
lineHeightLabel: "라디오 줄간격 (px)",
lineHeightLabel: "라디오 줄간격",
lineHeightUnitLabel: "(px)",
letterSpacingLabel: "라디오 자간 (px)",
letterSpacingLabel: "라디오 자간",
letterSpacingUnitLabel: "(px)",
fixedWidthLabel: "필드 고정 너비",
fixedWidthUnitLabel: "(px)",
paddingXLabel: "라디오 가로 패딩 (px)",
paddingXLabel: "라디오 가로 패딩",
paddingXUnitLabel: "(px)",
paddingYLabel: "라디오 세로 패딩 (px)",
paddingYLabel: "라디오 세로 패딩",
paddingYUnitLabel: "(px)",
optionGapLabel: "라디오 옵션 간격 (px)",
optionGapLabel: "라디오 옵션 간격",
optionGapUnitLabel: "(px)",
textColorLabel: "텍스트 색상",
@@ -89,7 +89,7 @@ const EDITOR_FORM_SELECT_PANEL_MESSAGES: Record<AppLocale, EditorFormSelectPanel
layoutOptionStacked: "Vertical (default)",
layoutOptionInline: "Horizontal (inline)",
labelGapLabel: "Label/field gap (px)",
labelGapLabel: "Label/field gap",
fieldLabelLabel: "Field label",
submitKeyLabel: "Submit key",
@@ -103,13 +103,13 @@ const EDITOR_FORM_SELECT_PANEL_MESSAGES: Record<AppLocale, EditorFormSelectPanel
styleSectionTitle: "Field style",
textSizeLabel: "Select text size (px)",
textSizeLabel: "Select text size",
textSizeUnitLabel: "(px)",
lineHeightLabel: "Select line height (px)",
lineHeightLabel: "Select line height",
lineHeightUnitLabel: "(px)",
letterSpacingLabel: "Select letter spacing (px)",
letterSpacingLabel: "Select letter spacing",
letterSpacingUnitLabel: "(px)",
widthModeLabel: "Field width",
@@ -120,10 +120,10 @@ const EDITOR_FORM_SELECT_PANEL_MESSAGES: Record<AppLocale, EditorFormSelectPanel
fixedWidthLabel: "Field fixed width",
fixedWidthUnitLabel: "(px)",
paddingXLabel: "Select horizontal padding (px)",
paddingXLabel: "Select horizontal padding",
paddingXUnitLabel: "(px)",
paddingYLabel: "Select vertical padding (px)",
paddingYLabel: "Select vertical padding",
paddingYUnitLabel: "(px)",
textColorLabel: "Field text color",
@@ -160,7 +160,7 @@ const EDITOR_FORM_SELECT_PANEL_MESSAGES: Record<AppLocale, EditorFormSelectPanel
layoutOptionStacked: "세로 (기본)",
layoutOptionInline: "가로 (인라인)",
labelGapLabel: "라벨/필드 간격 (px)",
labelGapLabel: "라벨/필드 간격",
fieldLabelLabel: "필드 라벨",
submitKeyLabel: "전송 키",
@@ -174,13 +174,13 @@ const EDITOR_FORM_SELECT_PANEL_MESSAGES: Record<AppLocale, EditorFormSelectPanel
styleSectionTitle: "필드 스타일",
textSizeLabel: "셀렉트 텍스트 크기 (px)",
textSizeLabel: "셀렉트 텍스트 크기",
textSizeUnitLabel: "(px)",
lineHeightLabel: "셀렉트 줄간격 (px)",
lineHeightLabel: "셀렉트 줄간격",
lineHeightUnitLabel: "(px)",
letterSpacingLabel: "셀렉트 자간 (px)",
letterSpacingLabel: "셀렉트 자간",
letterSpacingUnitLabel: "(px)",
widthModeLabel: "필드 너비",
@@ -191,10 +191,10 @@ const EDITOR_FORM_SELECT_PANEL_MESSAGES: Record<AppLocale, EditorFormSelectPanel
fixedWidthLabel: "필드 고정 너비",
fixedWidthUnitLabel: "(px)",
paddingXLabel: "셀렉트 가로 패딩 (px)",
paddingXLabel: "셀렉트 가로 패딩",
paddingXUnitLabel: "(px)",
paddingYLabel: "셀렉트 세로 패딩 (px)",
paddingYLabel: "셀렉트 세로 패딩",
paddingYUnitLabel: "(px)",
textColorLabel: "필드 텍스트 색상",
@@ -78,9 +78,9 @@ const EDITOR_IMAGE_PANEL_MESSAGES: Record<AppLocale, EditorImagePanelMessages> =
widthModeLabel: "Width mode",
widthModeAria: "Image width mode",
widthModeOptionAuto: "Fit to content",
widthModeOptionFixed: "Fixed width (px)",
widthModeOptionFixed: "Fixed width",
fixedWidthLabel: "Fixed width (px)",
fixedWidthLabel: "Fixed width",
fixedWidthUnitLabel: "(px)",
fixedWidthPresetSmall: "Small",
fixedWidthPresetMedium: "Medium",
@@ -123,9 +123,9 @@ const EDITOR_IMAGE_PANEL_MESSAGES: Record<AppLocale, EditorImagePanelMessages> =
widthModeLabel: "너비 모드",
widthModeAria: "이미지 너비 모드",
widthModeOptionAuto: "내용에 맞춤",
widthModeOptionFixed: "고정 너비 (px)",
widthModeOptionFixed: "고정 너비",
fixedWidthLabel: "고정 너비 (px)",
fixedWidthLabel: "고정 너비",
fixedWidthUnitLabel: "(px)",
fixedWidthPresetSmall: "작게",
fixedWidthPresetMedium: "보통",
@@ -64,7 +64,7 @@ const EDITOR_LIST_PANEL_MESSAGES: Record<AppLocale, EditorListPanelMessages> = {
styleSectionTitle: "List style",
fontSizeLabel: "Font size (px)",
fontSizeLabel: "Font size",
fontSizeUnitLabel: "(px)",
fontSizePresetSmall: "Small",
fontSizePresetMedium: "Medium",
@@ -95,7 +95,7 @@ const EDITOR_LIST_PANEL_MESSAGES: Record<AppLocale, EditorListPanelMessages> = {
bulletStyleOptionUpperRoman: "Upper roman (I.)",
bulletStyleOptionNone: "None",
gapLabel: "Item gap (px)",
gapLabel: "Item gap",
gapUnitLabel: "(px)",
gapPresetTight: "Tight",
gapPresetNormal: "Normal",
@@ -113,7 +113,7 @@ const EDITOR_LIST_PANEL_MESSAGES: Record<AppLocale, EditorListPanelMessages> = {
styleSectionTitle: "리스트 스타일",
fontSizeLabel: "글자 크기 (px)",
fontSizeLabel: "글자 크기",
fontSizeUnitLabel: "(px)",
fontSizePresetSmall: "작게",
fontSizePresetMedium: "보통",
@@ -144,7 +144,7 @@ const EDITOR_LIST_PANEL_MESSAGES: Record<AppLocale, EditorListPanelMessages> = {
bulletStyleOptionUpperRoman: "로마 숫자 대문자 (I.)",
bulletStyleOptionNone: "없음",
gapLabel: "아이템 간 여백 (px)",
gapLabel: "아이템 간 여백",
gapUnitLabel: "(px)",
gapPresetTight: "좁게",
gapPresetNormal: "보통",
@@ -117,12 +117,12 @@ const EDITOR_PROPERTIES_SIDEBAR_MESSAGES: Record<AppLocale, EditorPropertiesSide
"The label that appears on the button. For example: 'Get started now', 'Contact us'. Short, action-oriented phrases usually work best.",
},
{
label: "Horizontal padding (px)",
label: "Horizontal padding",
description:
"Controls the left and right inner spacing of the button. Larger values create a wider button that stands out more.",
},
{
label: "Vertical padding (px)",
label: "Vertical padding",
description:
"Controls the top and bottom inner spacing. Increasing this value makes the button taller and more prominent.",
},
@@ -210,7 +210,7 @@ const EDITOR_PROPERTIES_SIDEBAR_MESSAGES: Record<AppLocale, EditorPropertiesSide
"Controls whether the image is aligned to the left, center, or right inside the container.",
},
{
label: "Width mode / fixed width (px)",
label: "Width mode / fixed width",
description:
"Choose between auto width (fit content) and a fixed width in px. For thumbnail grids, fixed widths often create a more stable layout.",
},
@@ -238,7 +238,7 @@ const EDITOR_PROPERTIES_SIDEBAR_MESSAGES: Record<AppLocale, EditorPropertiesSide
"Align the whole list to the left, center, or right. Checklists are typically left-aligned, while short feature summaries often use center alignment.",
},
{
label: "Font size (px)",
label: "Font size",
description:
"Controls the font size of list text. Slightly smaller than the main body copy can make it feel like supporting information.",
},
@@ -263,7 +263,7 @@ const EDITOR_PROPERTIES_SIDEBAR_MESSAGES: Record<AppLocale, EditorPropertiesSide
"Choose bullet shapes (●/○/■) or numbered styles (1., a., i.). Number/letter/Roman styles automatically become ordered lists.",
},
{
label: "Item gap (px)",
label: "Item gap",
description:
"Controls the vertical space between list items. For longer descriptions, use a larger gap for better readability.",
},
@@ -286,7 +286,7 @@ const EDITOR_PROPERTIES_SIDEBAR_MESSAGES: Record<AppLocale, EditorPropertiesSide
"Controls line thickness. A thin line is good for subtle separators, while a normal thickness clearly divides sections.",
},
{
label: "Length mode / fixed length (px)",
label: "Length mode / fixed length",
description:
"Choose whether the divider spans the full width, auto width, or a fixed length in px.",
},
@@ -362,7 +362,7 @@ const EDITOR_PROPERTIES_SIDEBAR_MESSAGES: Record<AppLocale, EditorPropertiesSide
"Controls whether the video is left, center, or right aligned inside its container.",
},
{
label: "Width mode / fixed width (px)",
label: "Width mode / fixed width",
description:
"Choose auto width, full width, or a fixed width in px for the video.",
},
@@ -405,12 +405,12 @@ const EDITOR_PROPERTIES_SIDEBAR_MESSAGES: Record<AppLocale, EditorPropertiesSide
"Add extra key/value pairs that are always included in the submission. Use one `key=value` per line. Example: `source=landing`.",
},
{
label: "Form width mode / fixed width (px)",
label: "Form width mode / fixed width",
description:
"Choose automatic width, full width, or a fixed px width. Contact forms often work well around 480640px.",
},
{
label: "Form vertical margin (px)",
label: "Form vertical margin",
description:
"Controls the vertical space above and below the form block.",
},
@@ -480,7 +480,7 @@ const EDITOR_PROPERTIES_SIDEBAR_MESSAGES: Record<AppLocale, EditorPropertiesSide
{
label: "Layout / label-field gap",
description:
"Choose stacked or inline layout for label and field, and adjust the gap between them (px) in inline mode.",
"Choose stacked or inline layout for label and field, and adjust the gap between them in inline mode.",
},
{
label: "Width / fixed width",
@@ -719,12 +719,12 @@ const EDITOR_PROPERTIES_SIDEBAR_MESSAGES: Record<AppLocale, EditorPropertiesSide
"버튼 위에 표시될 문구입니다. 예: '지금 시작하기', '문의 남기기'. 짧고 행동을 유도하는 문장을 사용하는 것이 좋습니다.",
},
{
label: "가로 패딩 (px)",
label: "가로 패딩",
description:
"버튼 양 옆의 여백을 조절합니다. 값이 클수록 버튼이 가로로 넓어져 더 강조됩니다.",
},
{
label: "세로 패딩 (px)",
label: "세로 패딩",
description:
"버튼 위·아래 여백을 조절합니다. 값이 클수록 버튼 높이가 높아져 더 눈에 띕니다.",
},
@@ -812,7 +812,7 @@ const EDITOR_PROPERTIES_SIDEBAR_MESSAGES: Record<AppLocale, EditorPropertiesSide
"이미지가 포함된 영역 안에서 왼쪽/가운데/오른쪽 중 어디에 위치할지 결정합니다.",
},
{
label: "너비 모드 / 고정 너비 (px)",
label: "너비 모드 / 고정 너비",
description:
"이미지를 내용 크기에 맞출지(auto) 또는 px 단위로 고정된 너비를 사용할지 선택합니다. 썸네일 그리드에서는 고정 너비를 사용하는 편이 레이아웃이 안정적입니다.",
},
@@ -840,7 +840,7 @@ const EDITOR_PROPERTIES_SIDEBAR_MESSAGES: Record<AppLocale, EditorPropertiesSide
"리스트 전체를 왼쪽/가운데/오른쪽 중 어디에 정렬할지 결정합니다. 체크리스트는 왼쪽 정렬, 특징 요약은 가운데 정렬이 자주 사용됩니다.",
},
{
label: "글자 크기 (px)",
label: "글자 크기",
description:
"리스트 텍스트의 폰트 크기를 조절합니다. 본문보다 약간 작게 설정하면 보조 정보 느낌을 줄 수 있습니다.",
},
@@ -865,7 +865,7 @@ const EDITOR_PROPERTIES_SIDEBAR_MESSAGES: Record<AppLocale, EditorPropertiesSide
"불릿(●/○/■) 또는 번호(1., a., i.) 형식을 선택합니다. 숫자/알파벳/로마 숫자 스타일을 선택하면 자동으로 순서형 리스트(ordered)가 됩니다.",
},
{
label: "아이템 간 여백 (px)",
label: "아이템 간 여백",
description:
"각 리스트 항목 사이의 세로 간격입니다. 설명이 긴 항목이 많다면 여백을 넉넉히 두어 가독성을 확보하세요.",
},
@@ -888,7 +888,7 @@ const EDITOR_PROPERTIES_SIDEBAR_MESSAGES: Record<AppLocale, EditorPropertiesSide
"선의 두께입니다. '얇게'는 가벼운 보조 구분선, '보통'은 섹션 경계를 확실히 나눌 때 사용합니다.",
},
{
label: "길이 모드 / 고정 길이 (px)",
label: "길이 모드 / 고정 길이",
description:
"구분선을 전체 폭으로 쓸지, 내용에 맞출지, 또는 px 단위의 고정 길이를 사용할지 선택합니다.",
},
@@ -964,7 +964,7 @@ const EDITOR_PROPERTIES_SIDEBAR_MESSAGES: Record<AppLocale, EditorPropertiesSide
"비디오를 컨테이너 안에서 왼쪽/가운데/오른쪽 중 어디에 위치시킬지 결정합니다.",
},
{
label: "비디오 너비 모드 / 고정 너비 (px)",
label: "비디오 너비 모드 / 고정 너비",
description:
"비디오를 내용 너비에 맞출지, 가로 전체를 채울지, 특정 px 너비로 고정할지 선택합니다.",
},
@@ -1007,12 +1007,12 @@ const EDITOR_PROPERTIES_SIDEBAR_MESSAGES: Record<AppLocale, EditorPropertiesSide
"`key=value` 형식으로 줄바꿈해 작성하면, 모든 폼 제출에 공통으로 포함될 추가 파라미터를 지정할 수 있습니다. 예: `source=landing`.",
},
{
label: "폼 너비 모드 / 폼 고정 너비 (px)",
label: "폼 너비 모드 / 폼 고정 너비",
description:
"폼 전체의 가로 폭을 자동/전체 폭/고정 px 값 중에서 선택합니다. 문의 폼은 보통 480~640px 정도의 고정 폭이 읽기 좋습니다.",
},
{
label: "폼 위/아래 여백 (px)",
label: "폼 위/아래 여백",
description:
"폼 블록 위·아래에 들어가는 공백입니다. 페이지 내 다른 섹션과의 간격을 조절할 때 사용합니다.",
},
@@ -172,7 +172,7 @@ const EDITOR_SECTION_PANEL_MESSAGES: Record<AppLocale, EditorSectionPanelMessage
columnLayoutOptionThreeEqual: "3 columns (1/3 - 1/3 - 1/3)",
columnLayoutOptionCustom: "Custom",
maxWidthLabel: "Max width (px)",
maxWidthLabel: "Max width",
maxWidthUnitLabel: "(px)",
maxWidthPresetExtraNarrow: "Very narrow",
maxWidthPresetNarrow: "Narrow",
@@ -180,7 +180,7 @@ const EDITOR_SECTION_PANEL_MESSAGES: Record<AppLocale, EditorSectionPanelMessage
maxWidthPresetWide: "Wide",
maxWidthPresetExtraWide: "Very wide",
gapXLabel: "Column gap (px)",
gapXLabel: "Column gap",
gapXUnitLabel: "(px)",
gapXPresetZero: "0",
gapXPresetTight: "Tight",
@@ -268,7 +268,7 @@ const EDITOR_SECTION_PANEL_MESSAGES: Record<AppLocale, EditorSectionPanelMessage
columnLayoutOptionThreeEqual: "3열 (1/3 - 1/3 - 1/3)",
columnLayoutOptionCustom: "직접 조정",
maxWidthLabel: "최대 폭 (px)",
maxWidthLabel: "최대 폭",
maxWidthUnitLabel: "(px)",
maxWidthPresetExtraNarrow: "매우 좁게",
maxWidthPresetNarrow: "좁게",
@@ -276,7 +276,7 @@ const EDITOR_SECTION_PANEL_MESSAGES: Record<AppLocale, EditorSectionPanelMessage
maxWidthPresetWide: "넓게",
maxWidthPresetExtraWide: "아주 넓게",
gapXLabel: "컬럼 간 간격 (px)",
gapXLabel: "컬럼 간 간격",
gapXUnitLabel: "(px)",
gapXPresetZero: "0",
gapXPresetTight: "좁게",
@@ -69,7 +69,7 @@ const EDITOR_TEXT_PANEL_MESSAGES: Record<AppLocale, EditorTextPanelMessages> = {
letterSpacingLabel: "Letter spacing",
letterSpacingPresetAria: "Letter spacing preset",
letterSpacingSliderAria: "Letter spacing slider",
letterSpacingInputAria: "Letter spacing custom (px)",
letterSpacingInputAria: "Letter spacing custom",
letterSpacingPresetTighter: "Very tight",
letterSpacingPresetTight: "Tight",
letterSpacingPresetNormal: "Normal",
@@ -118,7 +118,7 @@ const EDITOR_TEXT_PANEL_MESSAGES: Record<AppLocale, EditorTextPanelMessages> = {
letterSpacingLabel: "글자 간격",
letterSpacingPresetAria: "글자 간격 프리셋",
letterSpacingSliderAria: "글자 간격 슬라이더",
letterSpacingInputAria: "글자 간격 커스텀 (px)",
letterSpacingInputAria: "글자 간격 커스텀",
letterSpacingPresetTighter: "아주 좁게",
letterSpacingPresetTight: "좁게",
letterSpacingPresetNormal: "보통",
@@ -111,9 +111,9 @@ const EDITOR_VIDEO_PANEL_MESSAGES: Record<AppLocale, EditorVideoPanelMessages> =
widthModeAria: "Video width mode",
widthModeOptionAuto: "Fit to content",
widthModeOptionFull: "Full width",
widthModeOptionFixed: "Fixed width (px)",
widthModeOptionFixed: "Fixed width",
fixedWidthLabel: "Fixed width (px)",
fixedWidthLabel: "Fixed width",
fixedWidthUnitLabel: "(px)",
fixedWidthPresetSmall: "Small",
fixedWidthPresetMedium: "Medium",
@@ -179,9 +179,9 @@ const EDITOR_VIDEO_PANEL_MESSAGES: Record<AppLocale, EditorVideoPanelMessages> =
widthModeAria: "비디오 너비 모드",
widthModeOptionAuto: "내용에 맞춤",
widthModeOptionFull: "가로 전체",
widthModeOptionFixed: "고정 너비 (px)",
widthModeOptionFixed: "고정 너비",
fixedWidthLabel: "고정 너비 (px)",
fixedWidthLabel: "고정 너비",
fixedWidthUnitLabel: "(px)",
fixedWidthPresetSmall: "작게",
fixedWidthPresetMedium: "보통",