-
Notifications
You must be signed in to change notification settings - Fork 120
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use different
ThemeConfig
for each locale (#100)
- Loading branch information
1 parent
bb71781
commit 12a367f
Showing
21 changed files
with
784 additions
and
654 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,116 +1,202 @@ | ||
import { existsSync, readdirSync, readFileSync } from "fs"; | ||
import { resolve } from "path/posix"; | ||
import { ExtendedSidebarItem } from "./sidebars/utils"; | ||
import { DefaultTheme, LocaleConfig } from "vitepress"; | ||
import DevelopSidebar from "./sidebars/develop"; | ||
import PlayersSidebar from './sidebars/players'; | ||
import { ExtendedSidebarItem } from "./sidebars/utils"; | ||
|
||
export function applyTranslations(locale: string, translationSource: { [key: string]: string; }, fallbackSource: { [key: string]: string }, sidebar: ExtendedSidebarItem[]): ExtendedSidebarItem[] { | ||
const sidebarCopy = JSON.parse(JSON.stringify(sidebar)); | ||
|
||
for (const item of sidebarCopy) { | ||
if (item.disableTranslation) continue; | ||
|
||
if (!translationSource[item.text]) { | ||
if (fallbackSource[item.text]) { | ||
item.text = fallbackSource[item.text]; | ||
} | ||
} else { | ||
item.text = translationSource[item.text]; | ||
} | ||
/** | ||
* Loads locales and generates a LocaleConfig object. | ||
* | ||
* @param rootDir - The root directory of the project. | ||
* @returns A LocaleConfig object with locales and their corresponding themeConfig. | ||
*/ | ||
export function loadLocales(rootDir: string): LocaleConfig<DefaultTheme.Config> { | ||
const translatedFolder = resolve(rootDir, "..", "translated"); | ||
const translatedFolders = readdirSync(translatedFolder, { withFileTypes: true }) | ||
.filter(dirent => dirent.isDirectory()) | ||
.map(dirent => dirent.name); | ||
|
||
if (item.link && locale !== "en_us" && item.process !== false) { | ||
// Prefix the link with the locale | ||
item.link = `/${locale}${item.link}`; | ||
const locales: LocaleConfig<DefaultTheme.Config> = { | ||
root: { | ||
label: 'English', | ||
lang: 'en', | ||
themeConfig: generateTranslatedThemeConfig(null) | ||
} | ||
}; | ||
|
||
if (item.items) { | ||
item.items = applyTranslations(locale, translationSource, fallbackSource, item.items); | ||
for (const folder of translatedFolders) { | ||
if (!existsSync(resolve(translatedFolder, folder, "index.md"))) { | ||
continue; | ||
} | ||
} | ||
|
||
return sidebarCopy; | ||
} | ||
let firstHalf: string = folder.slice(0, 2); | ||
let secondHalf: string = folder.slice(3, 5); | ||
|
||
export function generateTranslatedSidebars(_rootDir: string, sidebars: { [url: string]: ExtendedSidebarItem[]; }): { [localeUrl: string]: ExtendedSidebarItem[]; } { | ||
const sidebarResult = {}; | ||
let locale = new Intl.DisplayNames([`${firstHalf}-${secondHalf.toUpperCase()}`], { type: 'language' }); | ||
let localeName = locale?.of(`${firstHalf}-${secondHalf.toUpperCase()}`)!; | ||
|
||
const englishFallbacks = JSON.parse(readFileSync(resolve(_rootDir, "..", "sidebar_translations.json"), "utf-8")); | ||
// Capitalize the first letter of the locale name | ||
localeName = localeName.charAt(0).toUpperCase() + localeName.slice(1); | ||
|
||
// Create the default english sidebar. | ||
for (const sidebarPair of Object.entries(sidebars)) { | ||
const [url, sidebar] = sidebarPair; | ||
sidebarResult[url] = applyTranslations("en_us", englishFallbacks, englishFallbacks, sidebar); | ||
locales[folder] = { | ||
label: localeName, | ||
link: `/${folder}/`, | ||
lang: folder, | ||
themeConfig: generateTranslatedThemeConfig(folder), | ||
} | ||
} | ||
|
||
const translatedFolder = resolve(_rootDir, "..", "translated"); | ||
return locales; | ||
} | ||
|
||
// Get all folder names from the translated folder | ||
const translatedFolders = readdirSync(translatedFolder, { withFileTypes: true }) | ||
.filter(dirent => dirent.isDirectory()) | ||
.map(dirent => dirent.name); | ||
/** | ||
* Returns a resolving function for any navbar strings. | ||
* @param localeDir - The directory of the locale (null for English). | ||
*/ | ||
function getNavbarResolver(localeDir: string | null): (key: string) => string { | ||
// Load navbar_translations.json of locale and english. | ||
const fallbackTranslations = JSON.parse(readFileSync(resolve(__dirname, "..", "navbar_translations.json"), "utf-8")); | ||
let translations: any; | ||
|
||
if(localeDir == null) { | ||
translations = fallbackTranslations | ||
} else { | ||
if(!existsSync(resolve("translated", localeDir, "navbar_translations.json"))) { | ||
translations = fallbackTranslations; | ||
} else { | ||
translations = JSON.parse(readFileSync(resolve("translated", localeDir, "navbar_translations.json"), "utf-8")); | ||
} | ||
} | ||
|
||
for (const folder of translatedFolders) { | ||
const sidebarPath = resolve(translatedFolder, folder, "sidebar_translations.json") | ||
const indexPath = resolve(translatedFolder, folder, "index.md") | ||
return (key: string) => { | ||
return translations[key] ?? fallbackTranslations[key] ?? key; | ||
} | ||
} | ||
|
||
if (!existsSync(indexPath)) { | ||
continue; | ||
} | ||
/** | ||
* Generates a theme configuration for a given locale. | ||
* | ||
* @param localeDir - The directory of the locale (null for English). | ||
* @returns A theme configuration object. | ||
*/ | ||
function generateTranslatedThemeConfig(localeDir: string | null): DefaultTheme.Config { | ||
const navbarResolver = getNavbarResolver(localeDir); | ||
|
||
return { | ||
// https://vitepress.dev/reference/default-theme-config | ||
nav: [ | ||
{ text: navbarResolver('home'), link: 'https://fabricmc.net/' }, | ||
{ text: navbarResolver('download'), link: 'https://fabricmc.net/use' }, | ||
{ | ||
text: navbarResolver('contribute'), items: [ | ||
// TODO: Expand on this later, with guidelines for loader+loom potentially? | ||
{ | ||
text: navbarResolver('title'), | ||
link: `${localeDir ? `/${localeDir}` : ''}/contributing` | ||
}, | ||
{ | ||
text: navbarResolver('contribute.api'), | ||
link: 'https://github.com/FabricMC/fabric/blob/1.20.4/CONTRIBUTING.md' | ||
} | ||
] | ||
}, | ||
], | ||
|
||
// TODO: localise version switcher | ||
|
||
search: { | ||
provider: 'local' | ||
}, | ||
|
||
outline: "deep", | ||
|
||
sidebar: generateTranslatedSidebars(__dirname, { | ||
'/players/': PlayersSidebar, | ||
'/develop/': DevelopSidebar, | ||
}), | ||
|
||
editLink: { | ||
pattern: ({ filePath }) => { | ||
return `https://github.com/FabricMC/fabric-docs/edit/main/${filePath}` | ||
}, | ||
text: localeDir ? readTranslations(resolve(__dirname, localeDir))['github.edit'] : 'Edit this page on GitHub' | ||
}, | ||
|
||
socialLinks: [ | ||
{ icon: 'github', link: 'https://github.com/FabricMC/fabric-docs' }, | ||
{ icon: 'discord', link: 'https://discord.gg/v6v4pMv' } | ||
], | ||
|
||
logo: "/logo.png", | ||
|
||
siteTitle: navbarResolver('title') | ||
}; | ||
} | ||
|
||
// If sidebar translations dont exist, use english fallback. | ||
if (!existsSync(sidebarPath)) { | ||
for (const sidebarPair of Object.entries(sidebars)) { | ||
const [url, sidebar] = sidebarPair; | ||
sidebarResult[`/${folder}${url}`] = sidebarResult[url]; | ||
/** | ||
* Generates translated sidebars for a given root directory and sidebars. | ||
* | ||
* @param rootDir - The root directory to generate translated sidebars for. | ||
* @param sidebars - An object containing sidebars to translate, keyed by URL. | ||
* @returns An object containing translated sidebars, keyed by locale URL. | ||
*/ | ||
function generateTranslatedSidebars(rootDir: string, sidebars: { [url: string]: ExtendedSidebarItem[] }): { [localeUrl: string]: ExtendedSidebarItem[] } { | ||
function applyTranslations( | ||
locale: string, | ||
translationSource: { [key: string]: string }, | ||
fallbackSource: { [key: string]: string }, | ||
sidebar: ExtendedSidebarItem[] | ||
): ExtendedSidebarItem[] { | ||
const sidebarCopy = JSON.parse(JSON.stringify(sidebar)); | ||
|
||
for (const item of sidebarCopy) { | ||
if (item.disableTranslation) continue; | ||
|
||
item.text = translationSource[item.text] ?? fallbackSource[item.text]; | ||
|
||
if (item.link && locale !== "en_us" && item.process !== false) { | ||
item.link = `/${locale}${item.link}`; | ||
} | ||
|
||
continue; | ||
if (item.items) { | ||
item.items = applyTranslations(locale, translationSource, fallbackSource, item.items); | ||
} | ||
} | ||
|
||
const translations: { [key: string]: string; } = JSON.parse(readFileSync(sidebarPath, "utf-8")); | ||
|
||
for (const sidebarPair of Object.entries(sidebars)) { | ||
const [url, sidebar] = sidebarPair; | ||
|
||
sidebarResult[`/${folder}${url}`] = applyTranslations(folder, translations, englishFallbacks, sidebar); | ||
} | ||
return sidebarCopy; | ||
} | ||
|
||
return sidebarResult; | ||
} | ||
|
||
export function loadLocales(_rootDir: string): LocaleConfig<DefaultTheme.Config> { | ||
const translatedFolder = resolve(_rootDir, "..", "translated"); | ||
|
||
// Get all folder names from the translated folder | ||
const englishFallbacks = readTranslations(resolve(rootDir, "..")); | ||
const translatedFolder = resolve(rootDir, "..", "translated"); | ||
const translatedFolders = readdirSync(translatedFolder, { withFileTypes: true }) | ||
.filter(dirent => dirent.isDirectory()) | ||
.map(dirent => dirent.name); | ||
|
||
const locales: LocaleConfig<DefaultTheme.Config> = {}; | ||
const translatedSidebars: { [localeUrl: string]: ExtendedSidebarItem[] } = {}; | ||
|
||
for (const folder of translatedFolders) { | ||
const indexPath = resolve(translatedFolder, folder, "index.md") | ||
for (const sidebarPair of Object.entries(sidebars)) { | ||
const [url, sidebar] = sidebarPair; | ||
translatedSidebars[url] = applyTranslations("en_us", englishFallbacks, englishFallbacks, sidebar); | ||
} | ||
|
||
// Dont add language if index.md does not exist | ||
if (!existsSync(indexPath)) { | ||
continue; | ||
for (const folder of translatedFolders) { | ||
const translations = readTranslations(resolve(translatedFolder, folder)); | ||
for (const sidebarPair of Object.entries(sidebars)) { | ||
const [url, sidebar] = sidebarPair; | ||
translatedSidebars[`/${folder}${url}`] = applyTranslations(folder, translations, englishFallbacks, sidebar); | ||
} | ||
} | ||
|
||
let firstHalf: string = folder.slice(0, 2); | ||
let secondHalf: string = folder.slice(3, 5); | ||
|
||
let locale = new Intl.DisplayNames([`${firstHalf}-${secondHalf.toUpperCase()}`], { type: 'language' }); | ||
let localeName = locale?.of(`${firstHalf}-${secondHalf.toUpperCase()}`)!; | ||
|
||
// Capitalize the first letter of the locale name | ||
localeName = localeName.charAt(0).toUpperCase() + localeName.slice(1); | ||
return translatedSidebars; | ||
} | ||
|
||
locales[folder] = { | ||
label: localeName, | ||
link: `/${folder}/`, | ||
lang: folder, | ||
} | ||
function readTranslations(folder: string | null): { [key: string]: string } { | ||
folder ??= resolve(__dirname, '..'); | ||
const sidebarPath = resolve(folder, "sidebar_translations.json"); | ||
if (!existsSync(sidebarPath)) { | ||
return readTranslations(null); | ||
} | ||
|
||
return locales; | ||
return JSON.parse(readFileSync(sidebarPath, "utf-8")); | ||
} |
Oops, something went wrong.