From 23e49c6e6e63a518e704f82879a5fdcf268c51d8 Mon Sep 17 00:00:00 2001 From: INOUE Daisuke Date: Tue, 8 Apr 2025 22:14:04 +0900 Subject: 1st stage, only language switch. Thank you, MomentQYC ( https://github.com/MomentQYC ). Your first attemt encourage me. --- src/app.ts | 200 ++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 151 insertions(+), 49 deletions(-) (limited to 'src/app.ts') diff --git a/src/app.ts b/src/app.ts index 0708081..febc67d 100755 --- a/src/app.ts +++ b/src/app.ts @@ -1,6 +1,20 @@ import express from "express"; import hbs from "express-handlebars"; import cookieParser from "cookie-parser"; +import i18next from "i18next"; +import Backend from "i18next-fs-backend"; +import { LanguageDetector, handle } from 'i18next-http-middleware'; +import { createRequire } from 'module'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; +import path from 'path'; + +const require = createRequire(import.meta.url); +const handlebarsI18next = require('handlebars-i18next'); + +// ESモジュールで__dirnameを再現 +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); import routes from "./routes.js"; import frontend from "./routes/frontend.js"; @@ -11,6 +25,7 @@ import staticPages from "./routes/static.js"; import magicLink from "./routes/magicLink.js"; import { initEmailService } from "./lib/email.js"; +import { getI18nHelpers } from "./helpers.js"; import { activityPubContentType, alternateActivityPubContentType, @@ -20,55 +35,142 @@ const app = express(); app.locals.sendEmails = initEmailService(); -// View engine // -const hbsInstance = hbs.create({ - defaultLayout: "main", - partialsDir: ["views/partials/"], - layoutsDir: "views/layouts/", - helpers: { - plural: function (number: number, text: string) { - var singular = number === 1; - // If no text parameter was given, just return a conditional s. - if (typeof text !== "string") return singular ? "" : "s"; - // Split with regex into group1/group2 or group1(group3) - var match = text.match(/^([^()\/]+)(?:\/(.+))?(?:\((\w+)\))?/); - // If no match, just append a conditional s. - if (!match) return text + (singular ? "" : "s"); - // We have a good match, so fire away - return ( - (singular && match[1]) || // Singular case - match[2] || // Plural case: 'bagel/bagels' --> bagels - match[1] + (match[3] || "s") - ); // Plural case: 'bagel(s)' or 'bagel' --> bagels - }, - json: function (context: any) { - return JSON.stringify(context); +// ESモジュールで__dirnameを再現する部分を関数化 +const getLocalesPath = () => { + const __filename = fileURLToPath(import.meta.url); + const __dirname = dirname(__filename); + return path.join(__dirname, '..', 'locales'); +}; + +async function initializeApp() { + // Cookies // + app.use(cookieParser()); + + // カスタム言語検出ミドルウェア + // app.use((req, res, next) => { + // const acceptLanguage = req.headers['accept-language']; + // if (acceptLanguage && acceptLanguage.includes('ja')) { + // res.cookie('i18next', 'ja', { + // maxAge: 365 * 24 * 60 * 60 * 1000, + // httpOnly: true, + // sameSite: 'lax' + // }); + // } + // next(); + // }); + + // i18next configuration + await i18next + .use(Backend) + .use(LanguageDetector) + .init({ + backend: { + loadPath: path.join(getLocalesPath(), '{{lng}}.json'), + }, + fallbackLng: 'en', + preload: ['en', 'ja'], + supportedLngs: ['en', 'ja'], + nonExplicitSupportedLngs: true, + load: 'languageOnly', + debug: true, + detection: { + order: ['header', 'cookie'], + lookupHeader: 'accept-language', + lookupCookie: 'i18next', + caches: ['cookie'] + }, + interpolation: { + escapeValue: false + } + }); + + app.use(handle(i18next)); + + // 言語を明示的に切り替える + app.use((req, res, next) => { + const currentLanguage = i18next.language; + i18next.changeLanguage(req.language); + const newLanguage = i18next.language; + console.log('Language Change:', { + header: req.headers['accept-language'], + detected: req.language, + currentLanguage: currentLanguage, + newLanguage: newLanguage + }); + next(); + }); + + // デバッグ用 + app.use((req, res, next) => { + console.log('Language Detection:', { + header: req.headers['accept-language'], + detected: req.language, + i18next: i18next.language + }); + next(); + }); + + // View engine // + const hbsInstance = hbs.create({ + defaultLayout: "main", + partialsDir: ["views/partials/"], + layoutsDir: "views/layouts/", + helpers: { + plural: function (number: number, text: string) { + var singular = number === 1; + // If no text parameter was given, just return a conditional s. + if (typeof text !== "string") return singular ? "" : "s"; + // Split with regex into group1/group2 or group1(group3) + var match = text.match(/^([^()\/]+)(?:\/(.+))?(?:\((\w+)\))?/); + // If no match, just append a conditional s. + if (!match) return text + (singular ? "" : "s"); + // We have a good match, so fire away + return ( + (singular && match[1]) || // Singular case + match[2] || // Plural case: 'bagel/bagels' --> bagels + match[1] + (match[3] || "s") + ); // Plural case: 'bagel(s)' or 'bagel' --> bagels + }, + json: function (context: any) { + return JSON.stringify(context); + }, + // i18nextヘルパーを追加 + ...getI18nHelpers() }, - }, -}); -app.engine("handlebars", hbsInstance.engine); -app.set("view engine", "handlebars"); -app.set("hbsInstance", hbsInstance); - -// Static files // -app.use(express.static("public")); - -// Body parser // -app.use(express.json({ type: alternateActivityPubContentType })); -app.use(express.json({ type: activityPubContentType })); -app.use(express.json({ type: "application/json" })); -app.use(express.urlencoded({ extended: true })); - -// Cookies // -app.use(cookieParser()); - -// Router // -app.use("/", staticPages); -app.use("/", frontend); -app.use("/", activitypub); -app.use("/", event); -app.use("/", group); -app.use("/", magicLink); -app.use("/", routes); + }); + + // i18nextHelperの呼び出し方法を変更 + if (typeof handlebarsI18next === 'function') { + handlebarsI18next(hbsInstance.handlebars, i18next); + } else if (typeof handlebarsI18next.default === 'function') { + handlebarsI18next.default(hbsInstance.handlebars, i18next); + } else { + console.error('handlebars-i18next helper is not properly loaded'); + } + + app.engine("handlebars", hbsInstance.engine); + app.set("view engine", "handlebars"); + app.set("hbsInstance", hbsInstance); + + // Static files // + app.use(express.static("public")); + + // Body parser // + app.use(express.json({ type: alternateActivityPubContentType })); + app.use(express.json({ type: activityPubContentType })); + app.use(express.json({ type: "application/json" })); + app.use(express.urlencoded({ extended: true })); + + // Router // + app.use("/", staticPages); + app.use("/", frontend); + app.use("/", activitypub); + app.use("/", event); + app.use("/", group); + app.use("/", magicLink); + app.use("/", routes); +} + +initializeApp().catch(console.error); export default app; -- cgit v1.2.3 From 90bdf104d76674d307cbd50dc1cf3d973b663471 Mon Sep 17 00:00:00 2001 From: INOUE Daisuke Date: Tue, 8 Apr 2025 22:18:02 +0900 Subject: fix and add some translation keys. --- src/app.ts | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'src/app.ts') diff --git a/src/app.ts b/src/app.ts index febc67d..5fe0100 100755 --- a/src/app.ts +++ b/src/app.ts @@ -46,19 +46,6 @@ async function initializeApp() { // Cookies // app.use(cookieParser()); - // カスタム言語検出ミドルウェア - // app.use((req, res, next) => { - // const acceptLanguage = req.headers['accept-language']; - // if (acceptLanguage && acceptLanguage.includes('ja')) { - // res.cookie('i18next', 'ja', { - // maxAge: 365 * 24 * 60 * 60 * 1000, - // httpOnly: true, - // sameSite: 'lax' - // }); - // } - // next(); - // }); - // i18next configuration await i18next .use(Backend) -- cgit v1.2.3 From 1b57d9ea6513b81e538677f9ebf221d0c635f482 Mon Sep 17 00:00:00 2001 From: INOUE Daisuke Date: Tue, 8 Apr 2025 22:18:39 +0900 Subject: Plural with i18next --- src/app.ts | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) (limited to 'src/app.ts') diff --git a/src/app.ts b/src/app.ts index 5fe0100..ddfc101 100755 --- a/src/app.ts +++ b/src/app.ts @@ -1,5 +1,6 @@ import express from "express"; -import hbs from "express-handlebars"; +import hbs, { ExpressHandlebars } from "express-handlebars"; +import Handlebars from 'handlebars'; import cookieParser from "cookie-parser"; import i18next from "i18next"; import Backend from "i18next-fs-backend"; @@ -98,31 +99,20 @@ async function initializeApp() { }); // View engine // - const hbsInstance = hbs.create({ + const hbsInstance: ExpressHandlebars = hbs.create({ defaultLayout: "main", partialsDir: ["views/partials/"], layoutsDir: "views/layouts/", helpers: { - plural: function (number: number, text: string) { - var singular = number === 1; - // If no text parameter was given, just return a conditional s. - if (typeof text !== "string") return singular ? "" : "s"; - // Split with regex into group1/group2 or group1(group3) - var match = text.match(/^([^()\/]+)(?:\/(.+))?(?:\((\w+)\))?/); - // If no match, just append a conditional s. - if (!match) return text + (singular ? "" : "s"); - // We have a good match, so fire away - return ( - (singular && match[1]) || // Singular case - match[2] || // Plural case: 'bagel/bagels' --> bagels - match[1] + (match[3] || "s") - ); // Plural case: 'bagel(s)' or 'bagel' --> bagels - }, json: function (context: any) { return JSON.stringify(context); }, // i18nextヘルパーを追加 - ...getI18nHelpers() + ...getI18nHelpers(), + plural: function (key: string, count: number, options: any) { // ★plural ヘルパーを登録 + const translation = i18next.t(key, { count: count }); + return translation; + } }, }); @@ -135,6 +125,12 @@ async function initializeApp() { console.error('handlebars-i18next helper is not properly loaded'); } + + (hbsInstance.handlebars as typeof Handlebars).registerHelper('pluralize', function(count: number, key: string, options: any) { + const translation = i18next.t(key, { count: count }); + return translation; + }); + app.engine("handlebars", hbsInstance.engine); app.set("view engine", "handlebars"); app.set("hbsInstance", hbsInstance); -- cgit v1.2.3 From b6c5301bef843eab1262faca8548df204908b663 Mon Sep 17 00:00:00 2001 From: INOUE Daisuke Date: Tue, 8 Apr 2025 22:20:04 +0900 Subject: Add 'en-US', change preload language --- src/app.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/app.ts') diff --git a/src/app.ts b/src/app.ts index ddfc101..9828905 100755 --- a/src/app.ts +++ b/src/app.ts @@ -56,8 +56,8 @@ async function initializeApp() { loadPath: path.join(getLocalesPath(), '{{lng}}.json'), }, fallbackLng: 'en', - preload: ['en', 'ja'], - supportedLngs: ['en', 'ja'], + preload: ['en-US', 'ja'], + supportedLngs: ['en','en-US', 'ja'], nonExplicitSupportedLngs: true, load: 'languageOnly', debug: true, -- cgit v1.2.3 From f2ee19f15a78125a1dc2ba8b9c175dd9831e5700 Mon Sep 17 00:00:00 2001 From: INOUE Daisuke Date: Thu, 20 Mar 2025 22:54:38 +0900 Subject: hidden attendees (? people) --- src/app.ts | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src/app.ts') diff --git a/src/app.ts b/src/app.ts index 9828905..9301484 100755 --- a/src/app.ts +++ b/src/app.ts @@ -125,12 +125,6 @@ async function initializeApp() { console.error('handlebars-i18next helper is not properly loaded'); } - - (hbsInstance.handlebars as typeof Handlebars).registerHelper('pluralize', function(count: number, key: string, options: any) { - const translation = i18next.t(key, { count: count }); - return translation; - }); - app.engine("handlebars", hbsInstance.engine); app.set("view engine", "handlebars"); app.set("hbsInstance", hbsInstance); -- cgit v1.2.3 From 73e8b168c3ffc4e3ffe30e50dd3e46ed70d909d8 Mon Sep 17 00:00:00 2001 From: INOUE Daisuke Date: Sat, 22 Mar 2025 22:55:46 +0900 Subject: some fix, moment.locale setting --- src/app.ts | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/app.ts') diff --git a/src/app.ts b/src/app.ts index 9301484..a71bf30 100755 --- a/src/app.ts +++ b/src/app.ts @@ -31,6 +31,7 @@ import { activityPubContentType, alternateActivityPubContentType, } from "./lib/activitypub.js"; +import moment from "moment"; const app = express(); @@ -125,6 +126,10 @@ async function initializeApp() { console.error('handlebars-i18next helper is not properly loaded'); } + i18next.on('languageChanged', function(lng) { + moment.locale(lng); + }); + app.engine("handlebars", hbsInstance.engine); app.set("view engine", "handlebars"); app.set("hbsInstance", hbsInstance); -- cgit v1.2.3 From 15151fb2de8bfa8b934a4705150c4e7aef611ec3 Mon Sep 17 00:00:00 2001 From: INOUE Daisuke Date: Mon, 24 Mar 2025 21:38:47 +0900 Subject: remove i18n debug code --- src/app.ts | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'src/app.ts') diff --git a/src/app.ts b/src/app.ts index a71bf30..47bb2d1 100755 --- a/src/app.ts +++ b/src/app.ts @@ -61,7 +61,7 @@ async function initializeApp() { supportedLngs: ['en','en-US', 'ja'], nonExplicitSupportedLngs: true, load: 'languageOnly', - debug: true, + debug: false, detection: { order: ['header', 'cookie'], lookupHeader: 'accept-language', @@ -80,24 +80,24 @@ async function initializeApp() { const currentLanguage = i18next.language; i18next.changeLanguage(req.language); const newLanguage = i18next.language; - console.log('Language Change:', { - header: req.headers['accept-language'], - detected: req.language, - currentLanguage: currentLanguage, - newLanguage: newLanguage - }); +// console.log('Language Change:', { +// header: req.headers['accept-language'], +// detected: req.language, +// currentLanguage: currentLanguage, +// newLanguage: newLanguage +// }); next(); }); - // デバッグ用 - app.use((req, res, next) => { - console.log('Language Detection:', { - header: req.headers['accept-language'], - detected: req.language, - i18next: i18next.language - }); - next(); - }); +// // デバッグ用 +// app.use((req, res, next) => { +// console.log('Language Detection:', { +// header: req.headers['accept-language'], +// detected: req.language, +// i18next: i18next.language +// }); +// next(); +// }); // View engine // const hbsInstance: ExpressHandlebars = hbs.create({ -- cgit v1.2.3 From aace2c7e6ccb6e74df83faac74c427d43bfaf79b Mon Sep 17 00:00:00 2001 From: Gavin Mogan Date: Wed, 23 Apr 2025 15:06:54 -0700 Subject: Fix ReferenceError: nodemailerTransporter is not defined Part of https://github.com/lowercasename/gathio/pull/200 was migrating more code to use the shared init email function, but all the local usages of nodemailerTransporter were missed --- src/app.ts | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'src/app.ts') diff --git a/src/app.ts b/src/app.ts index 0708081..85ee64e 100755 --- a/src/app.ts +++ b/src/app.ts @@ -15,16 +15,28 @@ import { activityPubContentType, alternateActivityPubContentType, } from "./lib/activitypub.js"; +import getConfig from "./lib/config.js"; const app = express(); +const config = getConfig(); -app.locals.sendEmails = initEmailService(); +initEmailService().then((sendEmails) => (app.locals.sendEmails = sendEmails)); // View engine // const hbsInstance = hbs.create({ defaultLayout: "main", partialsDir: ["views/partials/"], layoutsDir: "views/layouts/", + runtimeOptions: { + data: { + domain: config.general.domain, + contactEmail: config.general.email, + siteName: config.general.site_name, + mailService: config.general.mail_service, + siteLogo: config.general.email_logo_url, + isFederated: config.general.is_federated || true, + }, + }, helpers: { plural: function (number: number, text: string) { var singular = number === 1; @@ -46,6 +58,31 @@ const hbsInstance = hbs.create({ }, }, }); +app.locals.renderEmail = async function renderEmail( + template: string, + data: object +) { + const [html, text] = await Promise.all([ + hbsInstance.renderView( + `./views/emails/${template}Html.handlebars`, + { + cache: true, + layout: "email.handlebars", + ...data, + } + ), + hbsInstance.renderView( + `./views/emails/${template}Text.handlebars`, + { + cache: true, + layout: "email.handlebars", + ...data, + } + ), + ]); + return { html, text } +} + app.engine("handlebars", hbsInstance.engine); app.set("view engine", "handlebars"); app.set("hbsInstance", hbsInstance); -- cgit v1.2.3 From a8a17443c2d070d2d23920ffff7e4a43c905698c Mon Sep 17 00:00:00 2001 From: Gavin Mogan Date: Wed, 23 Apr 2025 17:27:55 -0700 Subject: Refactor for everywhere to use sendEmailFromTemplate everywhere * Created a singleton to house handlebars so req doesn't need to be passed everywhere (should make unit testing easier later) * Subjectline for sendgrid and nodemailer are both always prefixed in sendEmail() * removed prefix subjectline from all other email places * added a couple if (!event) { return 404 } to help make typescript happy * some minor eslint auto fixes (looks like let => const where it can) --- src/app.ts | 68 +++----------------------------------------------------------- 1 file changed, 3 insertions(+), 65 deletions(-) (limited to 'src/app.ts') diff --git a/src/app.ts b/src/app.ts index 85ee64e..5f7c024 100755 --- a/src/app.ts +++ b/src/app.ts @@ -1,5 +1,4 @@ import express from "express"; -import hbs from "express-handlebars"; import cookieParser from "cookie-parser"; import routes from "./routes.js"; @@ -15,77 +14,16 @@ import { activityPubContentType, alternateActivityPubContentType, } from "./lib/activitypub.js"; -import getConfig from "./lib/config.js"; +import { HandlebarsSingleton } from "./lib/handlebars.js"; const app = express(); -const config = getConfig(); initEmailService().then((sendEmails) => (app.locals.sendEmails = sendEmails)); // View engine // -const hbsInstance = hbs.create({ - defaultLayout: "main", - partialsDir: ["views/partials/"], - layoutsDir: "views/layouts/", - runtimeOptions: { - data: { - domain: config.general.domain, - contactEmail: config.general.email, - siteName: config.general.site_name, - mailService: config.general.mail_service, - siteLogo: config.general.email_logo_url, - isFederated: config.general.is_federated || true, - }, - }, - helpers: { - plural: function (number: number, text: string) { - var singular = number === 1; - // If no text parameter was given, just return a conditional s. - if (typeof text !== "string") return singular ? "" : "s"; - // Split with regex into group1/group2 or group1(group3) - var match = text.match(/^([^()\/]+)(?:\/(.+))?(?:\((\w+)\))?/); - // If no match, just append a conditional s. - if (!match) return text + (singular ? "" : "s"); - // We have a good match, so fire away - return ( - (singular && match[1]) || // Singular case - match[2] || // Plural case: 'bagel/bagels' --> bagels - match[1] + (match[3] || "s") - ); // Plural case: 'bagel(s)' or 'bagel' --> bagels - }, - json: function (context: any) { - return JSON.stringify(context); - }, - }, -}); -app.locals.renderEmail = async function renderEmail( - template: string, - data: object -) { - const [html, text] = await Promise.all([ - hbsInstance.renderView( - `./views/emails/${template}Html.handlebars`, - { - cache: true, - layout: "email.handlebars", - ...data, - } - ), - hbsInstance.renderView( - `./views/emails/${template}Text.handlebars`, - { - cache: true, - layout: "email.handlebars", - ...data, - } - ), - ]); - return { html, text } -} - -app.engine("handlebars", hbsInstance.engine); +app.engine("handlebars", HandlebarsSingleton.instance.engine); app.set("view engine", "handlebars"); -app.set("hbsInstance", hbsInstance); +app.set("hbsInstance", HandlebarsSingleton.instance); // Static files // app.use(express.static("public")); -- cgit v1.2.3 From 14041a319cace03cfc23c0a919ed81fb141f88ce Mon Sep 17 00:00:00 2001 From: Gavin Mogan Date: Fri, 25 Apr 2025 21:43:39 -0700 Subject: Refactor to have email service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move hbsInstance back to app * Add email and hbs to req so typescript 🎉🎉🎉 * Init Email and config once --- src/app.ts | 47 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) (limited to 'src/app.ts') diff --git a/src/app.ts b/src/app.ts index 5f7c024..7ed535c 100755 --- a/src/app.ts +++ b/src/app.ts @@ -1,5 +1,6 @@ import express from "express"; import cookieParser from "cookie-parser"; +import { create as createHandlebars, ExpressHandlebars } from "express-handlebars"; import routes from "./routes.js"; import frontend from "./routes/frontend.js"; @@ -8,22 +9,56 @@ import event from "./routes/event.js"; import group from "./routes/group.js"; import staticPages from "./routes/static.js"; import magicLink from "./routes/magicLink.js"; - -import { initEmailService } from "./lib/email.js"; import { activityPubContentType, alternateActivityPubContentType, } from "./lib/activitypub.js"; -import { HandlebarsSingleton } from "./lib/handlebars.js"; +import { EmailService } from "./lib/email.js"; +import getConfig from "./lib/config.js"; const app = express(); +const config = getConfig(); + +const hbsInstance = createHandlebars({ + defaultLayout: "main", + partialsDir: ["views/partials/"], + layoutsDir: "views/layouts/", + helpers: { + plural: function (number: number, text: string) { + const singular = number === 1; + // If no text parameter was given, just return a conditional s. + if (typeof text !== "string") return singular ? "" : "s"; + // Split with regex into group1/group2 or group1(group3) + const match = text.match(/^([^()\/]+)(?:\/(.+))?(?:\((\w+)\))?/); + // If no match, just append a conditional s. + if (!match) return text + (singular ? "" : "s"); + // We have a good match, so fire away + return ( + (singular && match[1]) || // Singular case + match[2] || // Plural case: 'bagel/bagels' --> bagels + match[1] + (match[3] || "s") + ); // Plural case: 'bagel(s)' or 'bagel' --> bagels + }, + json: function (context: object) { + return JSON.stringify(context); + }, + }, +}); + +const emailService = new EmailService(config, hbsInstance); +emailService.verify(); -initEmailService().then((sendEmails) => (app.locals.sendEmails = sendEmails)); +app.use((req: express.Request, _: express.Response, next: express.NextFunction) => { + req.hbsInstance = hbsInstance; + req.emailService = emailService; + next() + return +}) // View engine // -app.engine("handlebars", HandlebarsSingleton.instance.engine); +app.engine("handlebars", hbsInstance.engine); app.set("view engine", "handlebars"); -app.set("hbsInstance", HandlebarsSingleton.instance); +app.set("hbsInstance", hbsInstance); // Static files // app.use(express.static("public")); -- cgit v1.2.3 From 889bae2029211abfd61a25ddecd7eb5b0f4a2c90 Mon Sep 17 00:00:00 2001 From: INOUE Daisuke Date: Sun, 27 Apr 2025 23:40:06 +0900 Subject: translate Japanese comments to English --- src/app.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src/app.ts') diff --git a/src/app.ts b/src/app.ts index 47bb2d1..4cf37c8 100755 --- a/src/app.ts +++ b/src/app.ts @@ -13,7 +13,7 @@ import path from 'path'; const require = createRequire(import.meta.url); const handlebarsI18next = require('handlebars-i18next'); -// ESモジュールで__dirnameを再現 +// Recreate __dirname in ES module const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -37,7 +37,7 @@ const app = express(); app.locals.sendEmails = initEmailService(); -// ESモジュールで__dirnameを再現する部分を関数化 +// function to construct __dirname with ES module const getLocalesPath = () => { const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -75,11 +75,12 @@ async function initializeApp() { app.use(handle(i18next)); - // 言語を明示的に切り替える + // to Switch language app.use((req, res, next) => { const currentLanguage = i18next.language; i18next.changeLanguage(req.language); const newLanguage = i18next.language; +// Uncomment for debugging // console.log('Language Change:', { // header: req.headers['accept-language'], // detected: req.language, @@ -89,7 +90,7 @@ async function initializeApp() { next(); }); -// // デバッグ用 +// Uncomment for debugging // app.use((req, res, next) => { // console.log('Language Detection:', { // header: req.headers['accept-language'], @@ -108,16 +109,16 @@ async function initializeApp() { json: function (context: any) { return JSON.stringify(context); }, - // i18nextヘルパーを追加 + // add i18next helpers ...getI18nHelpers(), - plural: function (key: string, count: number, options: any) { // ★plural ヘルパーを登録 + plural: function (key: string, count: number, options: any) { // Register the plural helper const translation = i18next.t(key, { count: count }); return translation; } }, }); - // i18nextHelperの呼び出し方法を変更 + // calling i18nextHelper if (typeof handlebarsI18next === 'function') { handlebarsI18next(hbsInstance.handlebars, i18next); } else if (typeof handlebarsI18next.default === 'function') { -- cgit v1.2.3 From 9286a9b97ec9aef5bcef965e01e1964521c84ab6 Mon Sep 17 00:00:00 2001 From: INOUE Daisuke Date: Thu, 1 May 2025 22:03:32 +0900 Subject: "en-us" removed, only "en" now. --- src/app.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/app.ts') diff --git a/src/app.ts b/src/app.ts index 4cf37c8..c4bcdcd 100755 --- a/src/app.ts +++ b/src/app.ts @@ -57,8 +57,8 @@ async function initializeApp() { loadPath: path.join(getLocalesPath(), '{{lng}}.json'), }, fallbackLng: 'en', - preload: ['en-US', 'ja'], - supportedLngs: ['en','en-US', 'ja'], + preload: ['en', 'ja'], + supportedLngs: ['en', 'ja'], nonExplicitSupportedLngs: true, load: 'languageOnly', debug: false, -- cgit v1.2.3