Enable getting started translations (#21842)
## Summary The Getting Started pages on the docs site (docs.twenty.com) were only ever available in English, never translated into the other supported languages. **Root cause:** The Getting Started section (added in #19728) was never added to the Crowdin source config (`crowdin-docs.yml`), so its `.mdx` files were never uploaded for translation. Only `user-guide`, `developers`, and `twenty-ui` were configured. This also surfaced a related bug: because the pages had no translations, the navigation generator fell back to the English page path for every language, duplicating paths like `getting-started/introduction` across all 14 language navs. Mintlify treats duplicate cross-language paths as undefined behavior, which broke the language switcher (it always redirected to `/getting-started/introduction`). ## Changes - `.github/crowdin-docs.yml` — add `getting-started/**/*.mdx` as a translation source so the pages get sent to Crowdin. - `packages/twenty-docs/scripts/fix-translated-links.sh` — add `getting-started` link-rewriting rules to match the other sections. - `packages/twenty-docs/scripts/generate-docs-json.ts` — only include a page in a non-default language when its translated file exists; drop empty groups/tabs (removes the duplicate cross-language paths that broke the switcher). - `packages/twenty-docs/docs.json` — regenerated. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21842?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -113,37 +113,54 @@ const buildLanguageEntry = (language: string): GeneratedLanguage => {
|
||||
|
||||
return {
|
||||
language,
|
||||
tabs: baseStructure.tabs.map((tab) => ({
|
||||
tab: translationMaps.tabLabels.get(tab.key) ?? tab.label,
|
||||
groups: tab.groups.map((group) =>
|
||||
buildGroup(group, translationMaps, language),
|
||||
),
|
||||
})),
|
||||
tabs: baseStructure.tabs
|
||||
.map((tab) => ({
|
||||
tab: translationMaps.tabLabels.get(tab.key) ?? tab.label,
|
||||
groups: tab.groups
|
||||
.map((group) => buildGroup(group, translationMaps, language))
|
||||
.filter((group): group is GeneratedGroup => group !== null),
|
||||
}))
|
||||
.filter((tab) => tab.groups.length > 0),
|
||||
};
|
||||
};
|
||||
|
||||
// Mintlify requires each page path to appear in only one language's navigation.
|
||||
// Duplicating a path across languages breaks the language switcher (it can no
|
||||
// longer resolve the equivalent page and falls back to the first page). So a
|
||||
// page is only included in a non-default language when its translation exists,
|
||||
// and empty groups/tabs are dropped entirely.
|
||||
const buildGroup = (
|
||||
group: BaseGroup,
|
||||
translations: TranslationMaps,
|
||||
language: string,
|
||||
): GeneratedGroup => ({
|
||||
group: translations.groupLabels.get(group.key) ?? group.label,
|
||||
...(group.icon ? { icon: group.icon } : {}),
|
||||
pages: group.pages.map((page) =>
|
||||
typeof page === 'string'
|
||||
? formatPageSlug(page, language)
|
||||
: buildGroup(page, translations, language),
|
||||
),
|
||||
});
|
||||
): GeneratedGroup | null => {
|
||||
const pages = group.pages
|
||||
.map((page) =>
|
||||
typeof page === 'string'
|
||||
? formatPageSlug(page, language)
|
||||
: buildGroup(page, translations, language),
|
||||
)
|
||||
.filter((page): page is string | GeneratedGroup => page !== null);
|
||||
|
||||
const formatPageSlug = (slug: string, language: string): string => {
|
||||
if (pages.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
group: translations.groupLabels.get(group.key) ?? group.label,
|
||||
...(group.icon ? { icon: group.icon } : {}),
|
||||
pages,
|
||||
};
|
||||
};
|
||||
|
||||
const formatPageSlug = (slug: string, language: string): string | null => {
|
||||
if (language === DEFAULT_LANGUAGE) {
|
||||
return slug;
|
||||
}
|
||||
|
||||
const localizedPagePath = path.join(localesRoot, language, `${slug}.mdx`);
|
||||
|
||||
return fs.existsSync(localizedPagePath) ? `l/${language}/${slug}` : slug;
|
||||
return fs.existsSync(localizedPagePath) ? `l/${language}/${slug}` : null;
|
||||
};
|
||||
|
||||
const hasLocaleContent = (language: string): boolean => {
|
||||
|
||||
Reference in New Issue
Block a user