feat: add default data for all locales (draft)#1044
Conversation
|
Warning: Component files have been updated but no migrations have been added. See https://github.com/yext/visual-editor/blob/main/packages/visual-editor/src/components/migrations/README.md for more information. |
commit: |
9a93e16 to
9738401
Compare
8456bb9 to
a83f797
Compare
… into default-locales
… into default-locales
… into default-locales
WalkthroughThis PR introduces a comprehensive system for managing localized default text across the visual editor's components. It adds 25 new locale translation files (covering locales from Czech to Chinese), establishes a centralized component default registry indexed by locale, creates utilities ( Sequence DiagramsequenceDiagram
participant Build as Build Process
participant Registry as Component Default Registry
participant Scanner as i18next Scanner
participant Component as Visual Editor Component
participant Utils as defaultContent Utils
participant Resolver as resolveComponentData
participant RenderEngine as React Renderer
Build->>Registry: Load all locale JSON files from locales/component-defaults/*
Registry-->>Build: componentDefaultRegistry (locale → key → string)
Build->>Scanner: Load supported locales from supportedLocales.json
Scanner->>Scanner: Update lngs config dynamically
Component->>Utils: defaultText("buttonText.label", "Button")
Utils->>Registry: Lookup key for current locale
alt Locale exists in registry
Registry-->>Utils: Return localized string
else Fallback to English
Registry-->>Utils: Return en default
end
Utils-->>Component: Return TranslatableString {en, fr, de, ...}
Component->>Resolver: resolveTranslatableType(value, locale)
Resolver->>Utils: Get locale-specific value
Utils->>Registry: Lookup locale in componentDefaultRegistry
Registry-->>Utils: String value
Utils-->>Resolver: Resolved value
Resolver-->>Component: Resolved text/element
Component->>RenderEngine: Render with resolved default value
RenderEngine-->>RenderEngine: Display localized text
Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 10
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
🤖 Fix all issues with AI agents
In `@packages/visual-editor/locales/component-defaults/fr/visual-editor.json`:
- Around line 1-7: The localized heading in aboutSection.heading uses the
translated placeholder "[[nom]]" which likely won't resolve because the code
expects the language-independent entity field placeholder "[[name]]"; update the
FR locale string to use the same placeholder token the component expects
(replace "[[nom]]" with "[[name]]") and verify AboutSection.tsx's interpolation
logic still finds and replaces [[name]] (or adjust the component if it expects a
different token), ensuring placeholder tokens remain consistent across locales
and the AboutSection.tsx rendering path.
In `@packages/visual-editor/locales/component-defaults/zh-TW/visual-editor.json`:
- Line 3: The locale entry under the "heading" key uses a translated placeholder
`[[姓名]]` which breaks the embedded-field resolver that expects ASCII field keys
via the regex /\[\[([a-zA-Z0-9._]+)\]\]/g; change the placeholder to the
canonical field key `[[name]]` (i.e., "heading": "關於[[name]]") and audit other
locale files for translated placeholders like `[[nome]]`, `[[namn]]`,
`[[naam]]`, `[[isim]]`, replacing them with the canonical `[[name]]` so the
resolver (which matches ASCII field identifiers) can correctly substitute
values.
In `@packages/visual-editor/scripts/generateComponentDefaultTranslations.ts`:
- Around line 168-194: The placeholder tokens like [[name]] must be protected
before calling translateText and restored afterwards; in the missingKeys async
handler (inside the Promise.allSettled loop) wrap any [[...]] placeholders in
the source string into safe temporary tokens, call translateText on the
tokenized text, then replace tokens back into the translated result (and also
apply removeEmbeddedContext if a context was embedded) before saving to
defaultsCache; ensure this tokenization/restoration runs regardless of whether
extractContextFromKey returned a context so placeholders are never sent raw to
the translation API (refer to functions/vars: extractContextFromKey,
embedContextInText, removeEmbeddedContext, translateText, defaultsCache,
missingKeys).
In
`@packages/visual-editor/src/components/pageSections/AboutSection/AboutSection.tsx`:
- Around line 206-209: Locale placeholder identifiers were translated (e.g., fr:
[[nom]]) which breaks findField() lookup because entity properties are
language-agnostic and expect the English property name; update all locale files
so aboutSection.heading uses the placeholder [[name]] (the constantValue passed
to defaultText in AboutSection.tsx) and scan other sections for similarly
translated placeholders (e.g., [[name]] vs [[nombre]]/[[Name]]) and normalize
them to the English property identifiers so findField() can resolve
document.name correctly.
In
`@packages/visual-editor/src/components/pageSections/EventSection/EventCard.tsx`:
- Around line 42-45: The missing localization key eventCard.description
referenced by defaultRichText("eventCard.description", ...) must be added to
every locale; update each locale's translation object (e.g., the en, zh, zh-TW,
es, tr, sk locale files) to include an eventCard.description entry with the
proper translated string (or confirm intentionally left in English), so that the
EventCard component's defaultRichText lookup finds a locale value instead of
always falling back to the English default.
In `@packages/visual-editor/src/components/pageSections/FAQsSection/FAQCard.tsx`:
- Around line 25-32: The locale files are missing the faqCard.question and
faqCard.answer keys used by defaultRichText, so add these two keys to every
locale object under the faqCard namespace (faqCard.question and faqCard.answer)
with appropriate localized rich-text strings (or copy the English fallback
content) so defaultRichText("faqCard.question", ...) and
defaultRichText("faqCard.answer", ...) can resolve for all locales; ensure the
keys match the same structure/format used by other rich-text translations so the
FAQCard component reads them correctly.
In
`@packages/visual-editor/src/components/pageSections/ProfessionalHeroSection.tsx`:
- Around line 727-730: The secondary CTA `link` is a URL but is wrapped with the
translation helper defaultText("professionalHeroSection.secondaryCtaLink", "#"),
which will send the placeholder "#" into the i18n pipeline; change the
assignment for `link` in ProfessionalHeroSection (the secondary CTA object where
`link: defaultText("professionalHeroSection.secondaryCtaLink", "#")`) to a plain
string (`link: "#"`) like the primary CTA so the URL is not translated.
In `@packages/visual-editor/src/utils/resolveYextEntityField.ts`:
- Around line 113-166: The fallback branch inside resolveYextEntityField
currently returns raw strings or inner objects when locale is missing; change
those to return the full translatable object shape like the locale-present
branch: for TranslatableString use return { ...data, en:
resolveEmbeddedFieldsInString(data.en, streamDocument, locale) }, for
TranslatableRichText use return { ...data, en: { ...data.en, html:
resolveEmbeddedFieldsInString(data.en.html, streamDocument, locale) } }, and for
the final missing case return the original data object (not an empty string);
keep use of resolveEmbeddedFieldsInString and preserve hasLocalizedValue and
other existing fields on data.
In `@packages/visual-editor/src/vite-plugin/templates/locator.tsx`:
- Around line 107-123: The call to processTemplateLayoutData passes layoutData
as a positional property name but the function expects rawLayoutData; update the
options object in the locator template where processTemplateLayoutData is
invoked (the block that currently sets layoutData and resolvedPuckData) to pass
rawLayoutData: layoutData so rawLayoutData is populated correctly; ensure the
rest of the call (streamDocument: document, templateId: "locator",
buildProcessedLayout using migrate and resolveAllData with locatorConfig)
remains unchanged.
In `@packages/visual-editor/src/vite-plugin/templates/main.tsx`:
- Around line 109-125: The call to processTemplateLayoutData is passing
layoutData instead of the required rawLayoutData, causing rawLayoutData to be
undefined; update the object passed to processTemplateLayoutData in main.tsx
(and replicate the same change in locator.tsx and directory.tsx) to use
rawLayoutData: layoutData while keeping the other properties (streamDocument:
document, templateId: "main", buildProcessedLayout: async () => { const
migratedData = migrate(layoutData, migrationRegistry, mainConfig, document);
return await resolveAllData(migratedData, mainConfig, { streamDocument: document
}); }). Ensure the symbol names layoutData, rawLayoutData,
processTemplateLayoutData, migrate, resolveAllData, migrationRegistry,
mainConfig, and document are used exactly as shown.
🟡 Minor comments (17)
packages/visual-editor/locales/component-defaults/pl/visual-editor.json-8-11 (1)
8-11:⚠️ Potential issue | 🟡 MinorFix incorrect Polish translation:
"header": "Chodnikowiec"should be"Nagłówek"The English source for this field is
"header": "Header". The Polish translation "Chodnikowiec" (sidewalk/pavement) is semantically incorrect. The proper Polish equivalent for "Header" in this context is"Nagłówek"(header/heading).packages/visual-editor/src/utils/resolveComponentData.tsx-144-150 (1)
144-150:⚠️ Potential issue | 🟡 MinorAvoid treating intentional empty translations as missing.
!value[locale]falls back to English even if the locale key exists but is intentionally empty. Consider falling back only when the locale value isnull/undefined.Suggested fix
- if (value.hasLocalizedValue === "true" && !value[locale]) { - const fallbackValue = value.en ?? ""; + const localizedValue = value[locale]; + if (value.hasLocalizedValue === "true" && localizedValue == null) { + const fallbackValue = value.en ?? ""; if (isRichText(fallbackValue)) { return toStringOrElement(fallbackValue); } return fallbackValue; }packages/visual-editor/locales/component-defaults/sk/visual-editor.json-74-76 (1)
74-76:⚠️ Potential issue | 🟡 MinorUntranslated "Insights" string in Slovak locale.
insightSection.sectionHeadingis left in English while othersectionHeadingvalues in the same file are properly translated (e.g.,nearbyLocations.sectionHeading→ "Polohy v okolí",photoGallery.sectionHeading→ "Galéria"). Provide Slovak translation to match the pattern.packages/visual-editor/locales/component-defaults/hu/visual-editor.json-74-76 (1)
74-76:⚠️ Potential issue | 🟡 Minor"Insights" left untranslated in Hungarian.
Line 75 has the English word "Insights" instead of a Hungarian translation (e.g., "Betekintések" or "Elemzések"). This was likely missed during automated translation.
packages/visual-editor/locales/component-defaults/hu/visual-editor.json-3-3 (1)
3-3:⚠️ Potential issue | 🟡 MinorLikely mistranslation: "Körülbelül" means "approximately", not "about (regarding)".
In Hungarian, "Körülbelül" conveys numerical approximation ("approximately"), not "about" in the sense of "regarding" or "information about." A more appropriate translation for "About [[name]]" would be something like "A(z) [[név]]-ról/ről" or "Rólunk" depending on context. This appears to be a machine-translation artifact.
packages/visual-editor/locales/component-defaults/nb/visual-editor.json-54-55 (1)
54-55:⚠️ Potential issue | 🟡 MinorSeveral Norwegian strings left untranslated in English.
Lines 55, 91, and 93 contain English text (
"Header Link","Call to Action") while the rest of the file is translated to Norwegian. These appear to be missed by the translation script.Also applies to: 89-94
packages/visual-editor/locales/component-defaults/fi/visual-editor.json-134-136 (1)
134-136:⚠️ Potential issue | 🟡 MinorPotentially awkward Finnish translation for "Featured Testimonials".
"Suositellut suosittelut"appears redundant — it roughly reads as "Recommended recommendations." Consider having a native Finnish speaker review this translation.packages/visual-editor/locales/component-defaults/da/visual-editor.json-18-20 (1)
18-20:⚠️ Potential issue | 🟡 MinorUntranslated strings:
directoryRootvalues remain in English.Both
breadcrumbs.directoryRoot(Line 19) anddirectory.directoryRoot(Line 32) are still "Directory Root" in English instead of Danish. Similarly,footer.sectionLabelon Line 52 is "Footer label" rather than a Danish translation. These appear to be machine translation gaps.Also applies to: 31-33
packages/visual-editor/locales/component-defaults/et/visual-editor.json-74-76 (1)
74-76:⚠️ Potential issue | 🟡 MinorUntranslated string:
insightSection.sectionHeadingis still in English.This value remains "Insights" while all other strings in this file are translated to Estonian. Other locale files have this translated (e.g., German: "Einblicke", Czech: "Postřehy", Danish: "Indsigt"). The Estonian equivalent would be something like "Ülevaated".
packages/visual-editor/locales/component-defaults/de/visual-editor.json-27-30 (1)
27-30:⚠️ Potential issue | 🟡 MinorMistranslation: "Taste" means keyboard key, not UI button.
"Taste" is used throughout this file for button labels (lines 29, 39, 63, 65, 69, 90, 92, 97, 109, 113, 118, 123), but in German it refers to a physical keyboard key. The standard German UI term is "Button" (widely adopted loanword) or "Schaltfläche". This affects all
buttonText,primaryButtonText, andsecondaryButtonTextentries.packages/visual-editor/locales/component-defaults/ja/visual-editor.json-1-137 (1)
1-137:⚠️ Potential issue | 🟡 MinorMachine-translated strings contain notable mistranslations.
A few entries stand out as incorrect or awkward:
- Line 6 —
"socialHeader": "私たちに従ってください": "従う" means "obey/comply", not "follow" in the social-media sense. Consider "フォローしてください" or "ソーシャルメディア".- Line 125 —
"name": "最初から最後まで": The English source"First Last"is a placeholder name (like "John Doe"), but this was translated as "From beginning to end". It should be a Japanese placeholder name, e.g."姓 名"or"山田 太郎".- Line 115 —
"subtitle": "字幕": "字幕" means movie/video subtitles. For a secondary heading,"サブタイトル"is more appropriate.Since these defaults are user-facing in the editor, consider having a native speaker review the machine-translated files — especially for languages where placeholder names and UI idioms don't translate literally.
packages/visual-editor/locales/component-defaults/es/visual-editor.json-122-127 (1)
122-127:⚠️ Potential issue | 🟡 MinorSame placeholder-name mistranslation as the Japanese file.
Line 125 —
"name": "Primero último"literally translates "First Last" word-by-word, but the intent is a placeholder person name (like "John Doe"). A more natural Spanish equivalent would be"Nombre Apellido"or a culturally common placeholder like"Juan Pérez".packages/visual-editor/locales/component-defaults/es/visual-editor.json-77-79 (1)
77-79:⚠️ Potential issue | 🟡 MinorCapitalization inconsistency:
"encontrar una ubicación"should be title-cased.Line 78 — Other headings in this file use sentence case with an initial capital (e.g.,
"Próximos eventos","Preguntas frecuentes"), but this one starts lowercase. Should be"Encontrar una ubicación".Proposed fix
"locator": { - "pageHeadingTitle": "encontrar una ubicación" + "pageHeadingTitle": "Encontrar una ubicación" },packages/visual-editor/locales/component-defaults/zh/visual-editor.json-46-46 (1)
46-46:⚠️ Potential issue | 🟡 MinorMissing empty
faqCardkey present in the English baseline.The
enlocale file has"faqCard": {}but it's absent here. Minor inconsistency — harmless since it's empty, but worth keeping in sync for the translation diff tooling.packages/visual-editor/locales/component-defaults/en/visual-editor.json-65-65 (1)
65-65:⚠️ Potential issue | 🟡 MinorInconsistent capitalization of "Call to Action" vs "Call To Action".
heroSection.primaryCtaLabel(line 65) uses"Call To Action"(Title Case) whileprimaryHeader.primaryCtaLabel(line 92) uses"Call to Action"(lowercase "to"). These serve the same purpose as default CTA labels — consider normalizing.Also applies to: 92-92
packages/visual-editor/locales/component-defaults/zh/visual-editor.json-115-115 (1)
115-115:⚠️ Potential issue | 🟡 MinorIncorrect Chinese translation for "subtitle".
"字幕"means video captions/subtitles, not a heading subtitle. The correct term in a UI/heading context is"副标题".Proposed fix
- "subtitle": "字幕" + "subtitle": "副标题"packages/visual-editor/locales/component-defaults/sv/visual-editor.json-115-115 (1)
115-115:⚠️ Potential issue | 🟡 MinorQuestionable machine translation:
"subtitle": "Texta"."Texta" in Swedish means "to text (someone)" or "to subtitle (a film)". For a UI label representing a subtitle/subheading, "Underrubrik" or "Undertitel" would be more appropriate. This is likely a Google Translate artifact. Since the PR TODO mentions testing with more locales, this may get caught in a review pass of all translations.
🧹 Nitpick comments (7)
packages/visual-editor/locales/component-defaults/pl/visual-editor.json (1)
131-136: Minor translation quality: "referencje" used for "testimonials"."Referencje" (Line 132, 135) more closely maps to "references" in Polish. A more natural translation for "testimonials" would be "opinie" or "rekomendacje". Similarly, on Line 107, "credentials" is rendered as "Referencje" which is a different meaning. Since these are auto-generated via Google Translate (per PR description), a quick human review pass on the Polish file would catch these semantic mismatches.
packages/visual-editor/src/components/footer/SecondaryFooterSlot.tsx (1)
11-16: Import and reusedefaultLinkfromExpandedFooter.tsxto avoid duplication.This local
defaultLinkis identical to the export inExpandedFooter.tsx(same key"footer.linkLabel", same shape).FooterExpandedLinkSectionSlot.tsxalready imports it from there, confirming the import path works and the export is intended for reuse. Consolidating to the shared export prevents drift if the default link structure changes.♻️ Suggested refactor
-import { defaultText } from "../../utils/defaultContent.ts"; - -const defaultLink = { - linkType: "URL" as const, - label: defaultText("footer.linkLabel", "Footer Link"), - link: "#", - openInNewTab: false, -}; +import { defaultLink } from "./ExpandedFooter.tsx";packages/visual-editor/locales/component-defaults/zh/visual-editor.json (1)
125-125: Consider a more natural Chinese name placeholder.
"第一个 最后一个"is a literal translation of "First Last" but reads unnaturally in Chinese. A conventional placeholder like"张三"(the Chinese equivalent of "John Doe") would be more idiomatic.packages/visual-editor/scripts/generateComponentDefaultTranslations.ts (2)
98-125: Unofficial Google Translate API endpoint is unreliable and has no rate-limiting.The
client=gtxendpoint is an undocumented, free API that Google can rate-limit or block without notice. Combined withPromise.allSettledon Line 171 firing all missing keys concurrently, this can trigger rate limits or IP bans during bulk translation runs.Consider:
- Using the official Cloud Translation API with an API key.
- Adding concurrency control (e.g., batching or a semaphore) to limit parallel requests.
18-39:extractContextFromKeyuses_separator but flattened keys use.— context feature is effectively dead code.
flattenproduces keys like"aboutSection.heading". SinceextractContextFromKeysplits on"_"(CONTEXT_SEPARATOR), it will never find a multi-part key in the current schema. TheembedContextInText/removeEmbeddedContextfunctions are therefore never invoked. If this is intentional scaffolding for future use, consider adding a comment. Otherwise, the separator should align with the actual key format.packages/visual-editor/src/utils/defaultLayoutTranslations.ts (2)
189-226: Static analysis:forEachcallback implicitly returns — usefor...ofto satisfy the linter.Biome flags Line 191 because
forEachcallbacks shouldn't return values, even thoughinjectLocalizedValuesisvoid. Switching tofor...ofsilences the lint and is more idiomatic for side-effect-only loops.Suggested fix
const injectLocalizedValues = (node: unknown, locales: string[]): void => { if (Array.isArray(node)) { - node.forEach((item) => injectLocalizedValues(item, locales)); + for (const item of node) { + injectLocalizedValues(item, locales); + } return; }
125-152: Ambiguous English values (e.g., "Button") will silently skip injection.The reverse-mapping approach via
enValueToKeysmeans any English string used by multiple component keys (like"Button"for bothctaWrapper.buttonTextandeventCard.buttonText) where those keys happen to have different locale translations will causecandidateValues.size !== 1, returningundefinedand skipping injection for that value.This is a safe design choice, but it could result in many common defaults (e.g., "Button", "Phone", "Text") not being injected. Consider logging a debug-level message when ambiguity is detected to help diagnose missing translations during development.
packages/visual-editor/locales/component-defaults/zh-TW/visual-editor.json
Outdated
Show resolved
Hide resolved
| constantValue: defaultText( | ||
| "aboutSection.heading", | ||
| "About [[name]]" | ||
| ), |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check how [[name]] placeholders are resolved — are they entity field references?
rg -n '\[\[name\]\]' --type=ts --type=tsx -C3
echo "---"
# Check all locale files for the aboutSection.heading key to see placeholder usage
fd 'visual-editor.json' packages/visual-editor/locales/component-defaults --exec grep -l 'aboutSection' {} \; | xargs -I{} sh -c 'echo "=== {} ===" && jq -r ".aboutSection.heading" {}'Repository: yext/visual-editor
Length of output: 2484
🏁 Script executed:
#!/bin/bash
# Find where defaultText is defined and how it processes placeholders
rg -n 'export.*defaultText|function.*defaultText' packages/visual-editor/src --type=ts -A5
echo "---"
# Search for placeholder resolution/template rendering logic
rg -n 'replace.*\[\[|\[\[.*\]\]' packages/visual-editor/src --type=ts -C2 | head -50Repository: yext/visual-editor
Length of output: 5299
🏁 Script executed:
cat packages/visual-editor/src/utils/resolveYextEntityField.tsRepository: yext/visual-editor
Length of output: 5852
Fix translated placeholder identifiers in locale files.
The placeholder resolution uses findField() to look up properties directly on the entity document object (e.g., [[name]] → document.name). Entity properties are language-agnostic and always use the English property names.
Translating the placeholder identifier breaks resolution in all non-English locales:
fr: [[nom]]→ tries to finddocument.nom(doesn't exist; property isname)es: [[nombre]]→ tries to finddocument.nombre(doesn't exist)de: [[Name]]→ tries to finddocument.Name(case-sensitive; property isname)- And 15+ other affected locales
Only en, en-GB, ro, cs, and sk use the correct identifier [[name]].
Update all locale files to use [[name]] for aboutSection.heading (and audit other sections for the same issue).
🤖 Prompt for AI Agents
In
`@packages/visual-editor/src/components/pageSections/AboutSection/AboutSection.tsx`
around lines 206 - 209, Locale placeholder identifiers were translated (e.g.,
fr: [[nom]]) which breaks findField() lookup because entity properties are
language-agnostic and expect the English property name; update all locale files
so aboutSection.heading uses the placeholder [[name]] (the constantValue passed
to defaultText in AboutSection.tsx) and scan other sections for similarly
translated placeholders (e.g., [[name]] vs [[nombre]]/[[Name]]) and normalize
them to the English property identifiers so findField() can resolve
document.name correctly.
packages/visual-editor/src/components/pageSections/EventSection/EventCard.tsx
Outdated
Show resolved
Hide resolved
packages/visual-editor/src/components/pageSections/FAQsSection/FAQCard.tsx
Outdated
Show resolved
Hide resolved
packages/visual-editor/src/components/pageSections/ProfessionalHeroSection.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Fix all issues with AI agents
In `@packages/visual-editor/locales/component-defaults/et/visual-editor.json`:
- Around line 74-76: The key insightSection.sectionHeading is still in English
("Insights"); update its value to the proper Estonian translation (for example
"Ülevaated" or "Teadmised") in the visual-editor.json so the locale file
contains the localized string for insightSection.sectionHeading.
In `@packages/visual-editor/locales/component-defaults/fi/visual-editor.json`:
- Around line 134-136: The Finnish translation for
testimonialSection.sectionHeading currently reads "Suositellut suosittelut",
which is awkwardly repetitive; update the value of
"testimonialSection"."sectionHeading" to a clearer phrase such as "Esitellyt
suosittelut" or "Suositellut suositukset" (pick the one that best fits the UI
context) to remove the near-duplicate wording and improve readability.
- Around line 105-116: In the professionalHeroSection locale object, fix two
Finnish translation errors: change the value of professionalName from
"Ammattilainen nimi" to the correct genitive form "Ammattilaisen nimi", and
change subtitle from "Tekstitys" to a more appropriate heading term like
"Alaotsikko"; update these keys (professionalHeroSection.professionalName and
professionalHeroSection.subtitle) in the JSON so the translations read
correctly.
In `@packages/visual-editor/locales/component-defaults/fr/visual-editor.json`:
- Line 36: Multiple keys use an inconsistent French translation for "Learn more"
— replace the non-idiomatic "Apprendre encore plus" with the idiomatic "En
savoir plus" for all relevant keys (e.g., textAndLinkLabel, insightCard.ctaLabel
and the other occurrences noted) so the translations are consistent across the
JSON; update each string value to "En savoir plus" while preserving the
surrounding JSON structure and keys.
In `@packages/visual-editor/locales/component-defaults/hu/visual-editor.json`:
- Around line 74-76: The JSON value for insightSection.sectionHeading is left in
English ("Insights"); update that value to a Hungarian translation (for example
"Betekintések" or "Cikkek") so it matches the rest of the locale file, ensuring
the key "insightSection" and its nested "sectionHeading" are preserved and only
the string value is changed.
In `@packages/visual-editor/locales/component-defaults/ja/visual-editor.json`:
- Around line 122-127: The translation for the placeholder name is incorrect:
replace the literal translation "最初から最後まで" under the teamCard.name key with a
proper Japanese placeholder for a person’s name (e.g., "姓 名" or "山田 太郎") so it
reads as a name placeholder rather than "from start to finish"; update the
teamCard.name value accordingly and scan other locale files generated by the
translation script for similar literal translations of "First Last" (e.g.,
Lithuanian/Estonian) to apply the same fix.
- Around line 3-6: The translation for the "socialHeader" key is too literal and
directive; update the value for "socialHeader" in the JSON (key: "socialHeader")
to a more natural social-media phrasing such as "フォローしてください" or "SNSでフォロー" so it
reads appropriately as "Follow Us" in Japanese.
In `@packages/visual-editor/src/utils/defaultLayoutTranslations.ts`:
- Around line 19-23: defaultLayoutsByTemplate currently parses JSON at module
load using JSON.parse on defaultLayoutData.main/directory/locator which will
throw and crash imports if any blob is malformed; change this to either wrap
each JSON.parse call in a try/catch that falls back to a safe default and logs
the error, or lazy-initialize parsing (e.g., replace the module-level object
with a getter/factory that parses on first access and handles parse failures).
Update references to defaultLayoutsByTemplate so consumers still get the same
shape (use VisualEditorTemplateId keys) while ensuring malformed JSON does not
throw during import.
🧹 Nitpick comments (4)
packages/visual-editor/src/utils/defaultLayoutTranslations.ts (2)
189-193:forEachcallback implicitly returns a value — usefor...ofinstead.Biome flags this because the arrow in
.forEach((item) => injectLocalizedValues(item, locales))implicitly returns the (void) result. Afor...ofloop is cleaner and avoids the lint warning.Suggested fix
const injectLocalizedValues = (node: unknown, locales: string[]): void => { if (Array.isArray(node)) { - node.forEach((item) => injectLocalizedValues(item, locales)); + for (const item of node) { + injectLocalizedValues(item, locales); + } return; }
154-170:extractDefaultRichTextInfoonly handles a single top-level HTML tag.The regex
/<(strong|span)>(.*?)<\/\1>/imatches only the first<strong>or<span>element. If default rich text ever contains multiple elements or nested tags, this will silently extract only the first match. This is fine if defaults are always simple single-wrapped text, but worth noting as a constraint.packages/visual-editor/scripts/generateComponentDefaultTranslations.ts (2)
55-98:flatten,unflatten,loadJsonSafe, andsaveJsonare duplicated fromgenerateTranslations.ts.These four utilities have near-identical implementations in both scripts. Consider extracting them into a shared module (e.g.,
scripts/translationUtils.ts) to reduce maintenance burden.
156-184: No concurrency limit on translation API calls.All
missingKeysfor a locale are fired concurrently viaPromise.allSettled. For locales with many missing keys, this could trigger rate limiting from the Google Translate API. Consider batching or throttling (e.g., processing in chunks of 10–20).
| "insightSection": { | ||
| "sectionHeading": "Insights" | ||
| }, |
There was a problem hiding this comment.
"Insights" left untranslated in Estonian.
insightSection.sectionHeading is still the English word "Insights" rather than an Estonian translation (e.g., "Ülevaated" or "Teadmised"). This was likely missed by the auto-translation step.
🤖 Prompt for AI Agents
In `@packages/visual-editor/locales/component-defaults/et/visual-editor.json`
around lines 74 - 76, The key insightSection.sectionHeading is still in English
("Insights"); update its value to the proper Estonian translation (for example
"Ülevaated" or "Teadmised") in the visual-editor.json so the locale file
contains the localized string for insightSection.sectionHeading.
| "professionalHeroSection": { | ||
| "businessName": "Yrityksen nimi", | ||
| "credentials": "Valtuustiedot", | ||
| "phoneLabel": "Puhelin", | ||
| "primaryButtonText": "Painike", | ||
| "primaryCtaLabel": "Ota minuun yhteyttä", | ||
| "professionalName": "Ammattilainen nimi", | ||
| "professionalTitle": "Ammattinimike", | ||
| "secondaryButtonText": "Painike", | ||
| "secondaryCtaLabel": "Lisätietoja", | ||
| "subtitle": "Tekstitys" | ||
| }, |
There was a problem hiding this comment.
Minor Finnish translation quality issues in professionalHeroSection.
- Line 111:
"Ammattilainen nimi"is grammatically incorrect — it should be"Ammattilaisen nimi"(genitive form) to mean "Professional's name." - Line 115:
"Tekstitys"means "subtitling" (as in film/TV captions), not a secondary heading. A more appropriate translation would be"Alaotsikko".
These may have been auto-generated; worth a quick review pass with a native speaker or improved prompt.
Suggested fix
- "professionalName": "Ammattilainen nimi",
+ "professionalName": "Ammattilaisen nimi",
...
- "subtitle": "Tekstitys"
+ "subtitle": "Alaotsikko"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "professionalHeroSection": { | |
| "businessName": "Yrityksen nimi", | |
| "credentials": "Valtuustiedot", | |
| "phoneLabel": "Puhelin", | |
| "primaryButtonText": "Painike", | |
| "primaryCtaLabel": "Ota minuun yhteyttä", | |
| "professionalName": "Ammattilainen nimi", | |
| "professionalTitle": "Ammattinimike", | |
| "secondaryButtonText": "Painike", | |
| "secondaryCtaLabel": "Lisätietoja", | |
| "subtitle": "Tekstitys" | |
| }, | |
| "professionalHeroSection": { | |
| "businessName": "Yrityksen nimi", | |
| "credentials": "Valtuustiedot", | |
| "phoneLabel": "Puhelin", | |
| "primaryButtonText": "Painike", | |
| "primaryCtaLabel": "Ota minuun yhteyttä", | |
| "professionalName": "Ammattilaisen nimi", | |
| "professionalTitle": "Ammattinimike", | |
| "secondaryButtonText": "Painike", | |
| "secondaryCtaLabel": "Lisätietoja", | |
| "subtitle": "Alaotsikko" | |
| }, |
🤖 Prompt for AI Agents
In `@packages/visual-editor/locales/component-defaults/fi/visual-editor.json`
around lines 105 - 116, In the professionalHeroSection locale object, fix two
Finnish translation errors: change the value of professionalName from
"Ammattilainen nimi" to the correct genitive form "Ammattilaisen nimi", and
change subtitle from "Tekstitys" to a more appropriate heading term like
"Alaotsikko"; update these keys (professionalHeroSection.professionalName and
professionalHeroSection.subtitle) in the JSON so the translations read
correctly.
| "testimonialSection": { | ||
| "sectionHeading": "Suositellut suosittelut" | ||
| } |
There was a problem hiding this comment.
"Suositellut suosittelut" reads awkwardly — near-duplicate words.
"Suositellut" (featured) and "suosittelut" (testimonials) differ by one letter, making this look like a typo. Consider "Esitellyt suosittelut" or "Suositellut suositukset" for clarity.
🤖 Prompt for AI Agents
In `@packages/visual-editor/locales/component-defaults/fi/visual-editor.json`
around lines 134 - 136, The Finnish translation for
testimonialSection.sectionHeading currently reads "Suositellut suosittelut",
which is awkwardly repetitive; update the value of
"testimonialSection"."sectionHeading" to a clearer phrase such as "Esitellyt
suosittelut" or "Suositellut suositukset" (pick the one that best fits the UI
context) to remove the near-duplicate wording and improve readability.
| }, | ||
| "enhancedCta": { | ||
| "getDirectionsLabel": "Obtenir un itinéraire", | ||
| "textAndLinkLabel": "Apprendre encore plus" |
There was a problem hiding this comment.
Inconsistent translation for "Learn more" across keys.
Some keys use "Apprendre encore plus" (lines 36, 40, 66, 98, 114, 119) while insightCard.ctaLabel on line 71 uses "En savoir plus". The latter is the more idiomatic French for "Learn more"; "Apprendre encore plus" back-translates to "Learn even more." Consider aligning all instances to "En savoir plus" for consistency and accuracy.
Also applies to: 40-40, 66-66, 71-71, 98-98, 114-114, 119-119
🤖 Prompt for AI Agents
In `@packages/visual-editor/locales/component-defaults/fr/visual-editor.json` at
line 36, Multiple keys use an inconsistent French translation for "Learn more" —
replace the non-idiomatic "Apprendre encore plus" with the idiomatic "En savoir
plus" for all relevant keys (e.g., textAndLinkLabel, insightCard.ctaLabel and
the other occurrences noted) so the translations are consistent across the JSON;
update each string value to "En savoir plus" while preserving the surrounding
JSON structure and keys.
| "insightSection": { | ||
| "sectionHeading": "Insights" | ||
| }, |
There was a problem hiding this comment.
"Insights" appears untranslated.
This string is left in English while every other value in the file is localized to Hungarian. Consider translating it (e.g., "Betekintések" or "Cikkek").
🤖 Prompt for AI Agents
In `@packages/visual-editor/locales/component-defaults/hu/visual-editor.json`
around lines 74 - 76, The JSON value for insightSection.sectionHeading is left
in English ("Insights"); update that value to a Hungarian translation (for
example "Betekintések" or "Cikkek") so it matches the rest of the locale file,
ensuring the key "insightSection" and its nested "sectionHeading" are preserved
and only the string value is changed.
| "heading": "[[name]]について", | ||
| "hoursHeader": "営業時間", | ||
| "servicesHeader": "提供されるサービス", | ||
| "socialHeader": "私たちに従ってください" |
There was a problem hiding this comment.
"Follow Us" social header translated too literally.
Line 6: "私たちに従ってください" means "Please obey/follow us" in a directive sense. For a social media "Follow Us" context, more natural Japanese would be "フォローしてください" or "SNSでフォロー".
🤖 Prompt for AI Agents
In `@packages/visual-editor/locales/component-defaults/ja/visual-editor.json`
around lines 3 - 6, The translation for the "socialHeader" key is too literal
and directive; update the value for "socialHeader" in the JSON (key:
"socialHeader") to a more natural social-media phrasing such as "フォローしてください" or
"SNSでフォロー" so it reads appropriately as "Follow Us" in Japanese.
| "teamCard": { | ||
| "buttonText": "ボタン", | ||
| "ctaLabel": "プロフィールにアクセス", | ||
| "name": "最初から最後まで", | ||
| "title": "アソシエイトエージェント" | ||
| }, |
There was a problem hiding this comment.
Mistranslation: "First Last" placeholder name translated as "最初から最後まで" (From start to finish).
The teamCard.name value "First Last" is a placeholder representing a person's name (first name + last name). The Japanese translation "最初から最後まで" literally means "From start to finish," which is a mistranslation. Consider using a Japanese placeholder name like "姓 名" or "太郎 山田".
The same issue likely affects other locale files generated by the translation script (e.g., Lithuanian has "Pirmas Paskutinis" and Estonian has "Esimene Viimane" which are also literal translations of "First"/"Last").
🤖 Prompt for AI Agents
In `@packages/visual-editor/locales/component-defaults/ja/visual-editor.json`
around lines 122 - 127, The translation for the placeholder name is incorrect:
replace the literal translation "最初から最後まで" under the teamCard.name key with a
proper Japanese placeholder for a person’s name (e.g., "姓 名" or "山田 太郎") so it
reads as a name placeholder rather than "from start to finish"; update the
teamCard.name value accordingly and scan other locale files generated by the
translation script for similar literal translations of "First Last" (e.g.,
Lithuanian/Estonian) to apply the same fix.
| const defaultLayoutsByTemplate: Record<VisualEditorTemplateId, unknown> = { | ||
| main: JSON.parse(defaultLayoutData.main), | ||
| directory: JSON.parse(defaultLayoutData.directory), | ||
| locator: JSON.parse(defaultLayoutData.locator), | ||
| }; |
There was a problem hiding this comment.
Module-level JSON.parse will crash the import if any default layout blob is malformed.
If defaultLayoutData.main, .directory, or .locator ever contains invalid JSON (e.g., during development or a build issue), this will throw at module load time with a cryptic parse error. Consider wrapping in a try/catch or lazy-initializing.
🤖 Prompt for AI Agents
In `@packages/visual-editor/src/utils/defaultLayoutTranslations.ts` around lines
19 - 23, defaultLayoutsByTemplate currently parses JSON at module load using
JSON.parse on defaultLayoutData.main/directory/locator which will throw and
crash imports if any blob is malformed; change this to either wrap each
JSON.parse call in a try/catch that falls back to a safe default and logs the
error, or lazy-initialize parsing (e.g., replace the module-level object with a
getter/factory that parses on first access and handles parse failures). Update
references to defaultLayoutsByTemplate so consumers still get the same shape
(use VisualEditorTemplateId keys) while ensuring malformed JSON does not throw
during import.
Intent:
defaultTextanddefaultRichTextnow build translatable defaults for all supported locales.defaultRichTextnow generates consistent html + json per locale usinggetDefaultRTF.packages/visual-editor/src/utils/defaultContent.tsdefaultText(...)/defaultRichText(...)instead of embedding en only defaults.transformProps)packages/visual-editor/src/utils/defaultLayoutTranslations.tspackages/visual-editor/scripts/generateComponentDefaultTranslations.tspackages/visual-editor/package.jsonTODO:
i18n:translate:component-defaultsesandfr