yuki.k4w411.net/_config/filters.js

158 lines
7.4 KiB
JavaScript

const { DateTime } = require("luxon");
module.exports = function (eleventyConfig, { TIME_ZONE, defaultLanguage }) {
// {{ post.date | date("dd/MM/yyyy") }} -> 18/10/2025
eleventyConfig.addFilter("date", function (dateObj, format = "dd/MM/yyyy") {
let dt = dateObj;
// handle string dates
if (typeof dateObj === "string") {
dt = DateTime.fromISO(dateObj, { zone: TIME_ZONE }).toJSDate();
}
// handle DateTime objects (from addDateParsing)
if (dateObj instanceof DateTime) {
dt = dateObj.toJSDate();
}
// check dt as valid Date object
if (!(dt instanceof Date) || isNaN(dt)) {
console.log("Invalid date input:", dateObj);
return "";
}
// format in TIME_ZONE
const formatted = DateTime.fromJSDate(dt, { zone: TIME_ZONE })
.toFormat(format);
console.log("Date input:", dt, "Formatted:", formatted, "Timezone:", TIME_ZONE);
return formatted;
});
// filters collections by current language
eleventyConfig.addFilter("i18n_filter", function (collection, limit = null) {
const lang = this.page.lang; // access page.lang from context
let filtered = collection.filter(item => item.data.lang === lang);
if (limit !== null) {
filtered = filtered.slice(0, limit);
}
return filtered;
});
// takes all collections and returns only the tags not matched
// key-objects so may repurpose under different name
eleventyConfig.addFilter("exclude_collections", function (collections, ...keysToExclude) {
if (!collections || typeof collections !== "object") {
console.warn("[exclude_collections] Invalid collections input:", collections);
return collections;
}
const result = {};
Object.keys(collections).forEach(key => {
if (!keysToExclude.includes(key)) {
result[key] = collections[key];
}
});
if (process.env.LOCALE_URL_DEBUG === "1" || process.env.LOCALE_URL_DEBUG === "true") {
console.warn("[excludeCollections] Excluded keys:", keysToExclude);
console.warn("[excludeCollections] Resulting keys:", Object.keys(result));
}
return result;
});
const LOCALE_URL_DEBUG = process.env.LOCALE_URL_DEBUG === "1" || process.env.LOCALE_URL_DEBUG === "true";
// locale_url replacement that uses pre-compile filesystem
eleventyConfig.addNunjucksFilter("locale_url_resolve", function (targetUrl, desiredLocale) {
const ctx = (this && this.ctx) ? this.ctx : {};
const collections = (ctx.collections) ? ctx.collections : {};
const all = collections.all || [];
if (!targetUrl || typeof targetUrl !== "string") return targetUrl;
if (!targetUrl.startsWith("/")) return targetUrl; // external or relative link -> leave as is
// determine locale to resolve to
const pageLang = desiredLocale || (ctx.page && ctx.page.lang) || ctx.locale || defaultLanguage;
const LOCALE_URL_DEBUG = process.env.LOCALE_URL_DEBUG === "1" || process.env.LOCALE_URL_DEBUG === "true";
if (LOCALE_URL_DEBUG) {
console.warn(`[locale_url_resolve] resolving targetUrl="${targetUrl}" desiredLocale="${desiredLocale}" pageLang="${pageLang}"`);
}
// special case for homepage
if (targetUrl === "/" || targetUrl === "/index/") {
if (pageLang === defaultLanguage) {
if (LOCALE_URL_DEBUG) console.warn(`[locale_url_resolve] homepage, default language (${defaultLanguage}) -> "/"`);
return "/";
}
const homepageUrl = `/${pageLang}/`;
if (LOCALE_URL_DEBUG) console.warn(`[locale_url_resolve] homepage, language (${pageLang}) -> "${homepageUrl}"`);
return homepageUrl;
}
// normalize targetUrl to include trailing slash for comparison
const normUrl = targetUrl.endsWith("/") ? targetUrl : `${targetUrl}/`;
// try to find the canonical (default language) page corresponding to targetUrl
let canonical = all.find(p => {
return (p.url === normUrl || p.url === targetUrl) && p.data && p.data.lang === defaultLanguage;
});
// if not found, try to find any page with that url (maybe targetUrl already localized)
if (!canonical) {
canonical = all.find(p => (p.url === normUrl || p.url === targetUrl));
}
if (LOCALE_URL_DEBUG) {
if (canonical) {
const cs = (canonical.page && canonical.page.filePathStem) ? canonical.page.filePathStem : "(no stem)";
const clang = (canonical.data && canonical.data.lang) ? canonical.data.lang : "(no lang)";
console.warn(`[locale_url_resolve] canonical found: url="${canonical.url}" filePathStem="${cs}" lang="${clang}"`);
} else {
console.warn(`[locale_url_resolve] canonical NOT found for targetUrl="${targetUrl}". Will fallback to prefixed URL.`);
}
}
// if cannot find canonical page, fall back to a prefixed URL (best effort)
if (!canonical) {
const fallback = `/${pageLang}${targetUrl}`.replace(/\/{2,}/g, "/");
if (LOCALE_URL_DEBUG) console.warn(`[locale_url_resolve] fallback -> "${fallback}"`);
return fallback;
}
// determine canonical filePathStem (the source input path without extension)
const canonicalLang = canonical.data && canonical.data.lang ? canonical.data.lang : defaultLanguage;
const canonicalStem = (canonical.page && canonical.page.filePathStem) ? canonical.page.filePathStem : "";
// remove the canonical lang prefix from the stem to create a "key" to match across locales.
// ie "/en/about" -> "/about", "/es/about" -> "/about"
const key = canonicalStem.replace(new RegExp(`^/${canonicalLang}`), "").replace(/^\/+/, "");
if (LOCALE_URL_DEBUG) {
console.warn(`[locale_url_resolve] canonicalLang="${canonicalLang}" canonicalStem="${canonicalStem}" key="${key}"`);
}
// find the localized page whose filePathStem ends with that key and whose lang matches pageLang.
const localized = all.find(p => {
const pLang = p.data && p.data.lang;
const pStem = (p.page && p.page.filePathStem) ? p.page.filePathStem : "";
// be defensive: ensure pLang exists
if (!pLang) return false;
return pLang === pageLang && pStem.endsWith(key);
});
if (localized && localized.url) {
if (LOCALE_URL_DEBUG) {
const ls = (localized.page && localized.page.filePathStem) ? localized.page.filePathStem : "(no stem)";
console.warn(`[locale_url_resolve] localized found: url="${localized.url}" filePathStem="${ls}" lang="${localized.data.lang}"`);
}
return localized.url;
}
// fallback to prefixed URL
const fallback2 = `/${pageLang}${targetUrl}`.replace(/\/{2,}/g, "/");
if (LOCALE_URL_DEBUG) console.warn(`[locale_url_resolve] localized NOT found for key="${key}" — fallback -> "${fallback2}"`);
return fallback2;
});
// turn on disabled nunjucks filters
eleventyConfig.addFilter("keys", obj => Object.keys(obj));
eleventyConfig.addFilter("values", obj => Object.values(obj));
};