Skip to content

Commit d3a3634

Browse files
chore: i18n refactoring (#748)
1 parent 788a4e5 commit d3a3634

5 files changed

Lines changed: 43 additions & 50 deletions

File tree

src/content/config.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { defineCollection, z } from 'astro:content';
22
import { docsLoader, i18nLoader } from '@astrojs/starlight/loaders';
33
import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
4-
import { starlightLocales } from '../utils/i18n.ts';
5-
import { getBaseDocId, localizeDocId } from '../utils/docsSlug.ts';
4+
import { starlightLocales, getBaseDocId, localizeDocId } from '../utils/i18n.ts';
65

76
export const collections = {
87
docs: defineCollection({

src/utils/docsSlug.ts

Lines changed: 0 additions & 43 deletions
This file was deleted.
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { describe, it, expect } from 'vitest';
2-
import { slugFromPath, getBaseDocId, localizeDocId } from './docsSlug';
3-
import { starlightLocales } from './i18n';
2+
import { slugFromPath, getBaseDocId, localizeDocId, starlightLocales } from './i18n';
43

54
const LOCALES = Object.keys(starlightLocales).filter(locale => locale !== 'root');
65

src/utils/i18n.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { slug as githubSlug } from 'github-slugger';
2+
13
import en from '../content/i18n/en.json';
24
import de from '../content/i18n/de.json';
35
import da from '../content/i18n/da.json';
@@ -34,3 +36,42 @@ export function sidebarLabel(key: SidebarTranslationKey) {
3436
},
3537
};
3638
}
39+
40+
/*
41+
In content-layer collections the entry `id` *is* Starlight's routing slug (there is no top-level `slug`).
42+
The glob loader builds that id from the frontmatter `slug` when present, dropping the locale folder prefix for pages
43+
shipped untranslated from the CMS - these helpers restore it. `entry` is the file path relative to src/content/docs (e.g. `tr/foo.md`).
44+
Astro's default path-based id: github-slug each segment, join with `/`, strip a trailing `/index`. Mirrors `getContentEntryIdAndSlug`
45+
*/
46+
export function slugFromPath(filePath: string): string {
47+
const withoutExt = filePath.replace(/\.[^/.]+$/, '');
48+
return withoutExt
49+
.split('/')
50+
.map(segment => githubSlug(segment))
51+
.join('/')
52+
.replace(/\/index$/, '');
53+
}
54+
55+
export function getBaseDocId(entry: string, frontmatterSlug?: unknown): string {
56+
return frontmatterSlug
57+
? String(frontmatterSlug).replace(/^\/+/, '')
58+
: slugFromPath(entry);
59+
}
60+
61+
export function localizeDocId(
62+
entry: string,
63+
id: string,
64+
localizedLocales: readonly string[],
65+
): string {
66+
const localeSegment = entry.split('/')[0];
67+
68+
if (
69+
localizedLocales.includes(localeSegment) &&
70+
id !== localeSegment &&
71+
!id.startsWith(`${localeSegment}/`)
72+
) {
73+
return `${localeSegment}/${id}`;
74+
}
75+
76+
return id;
77+
}

vercel.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,16 @@
66
{ "source": "/it/:slug/", "destination": "/:slug/", "statusCode": 302 },
77
{ "source": "/ru/:slug/", "destination": "/:slug/", "statusCode": 302 },
88
{ "source": "/uk/:slug/", "destination": "/:slug/", "statusCode": 302 },
9-
{ "source": "/zh/:slug/", "destination": "/:slug/", "statusCode": 302 },
109
{ "source": "/br/enterprise/:slug/", "destination": "/enterprise/:slug/", "statusCode": 302 },
1110
{ "source": "/hu/enterprise/:slug/", "destination": "/enterprise/:slug/", "statusCode": 302 },
1211
{ "source": "/it/enterprise/:slug/", "destination": "/enterprise/:slug/", "statusCode": 302 },
1312
{ "source": "/ru/enterprise/:slug/", "destination": "/enterprise/:slug/", "statusCode": 302 },
1413
{ "source": "/uk/enterprise/:slug/", "destination": "/enterprise/:slug/", "statusCode": 302 },
15-
{ "source": "/zh/enterprise/:slug/", "destination": "/enterprise/:slug/", "statusCode": 302 },
1614
{ "source": "/developer/br/:slug/", "destination": "/developer/:slug/", "statusCode": 302 },
1715
{ "source": "/developer/hu/:slug/", "destination": "/developer/:slug/", "statusCode": 302 },
1816
{ "source": "/developer/it/:slug/", "destination": "/developer/:slug/", "statusCode": 302 },
1917
{ "source": "/developer/ru/:slug/", "destination": "/developer/:slug/", "statusCode": 302 },
2018
{ "source": "/developer/uk/:slug/", "destination": "/developer/:slug/", "statusCode": 302 },
21-
{ "source": "/developer/zh/:slug/", "destination": "/developer/:slug/", "statusCode": 302 },
2219

2320
{ "source": "/enterprise/", "destination": "/enterprise/introduction/", "permanent": true },
2421
{ "source": "/developer/", "destination": "/developer/crowdin-apps-about/", "permanent": true },

0 commit comments

Comments
 (0)