diff --git a/README.md b/README.md index 796012b..1126887 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,7 @@ file does not exist, it is skipped without an error, ensuring flexibility. ```tsx import { define } from '@/utils/state.ts' +import { createTranslator } from 'jsr:@elsoul/fresh-i18n' export const handler = define.handlers({ GET(ctx) { @@ -151,9 +152,10 @@ export const handler = define.handlers({ }) export default define.page(function Home(props) { - console.log('props', props.state.t('common.title')) // Access translation data using getTranslation function via props + const { t } = createTranslator(props.state.translationData) return (
+ {t('common.title')} // Home or ホーム
) }) @@ -196,7 +198,7 @@ export const stateAtom = atom({ ogImage: '', noIndex: false, locale: 'en', - t: {}, + translationData: {}, path: '/', }) @@ -231,7 +233,7 @@ export function useTranslation() { */ const t = (key: string): string => { const keys = key.split('.') - let result: Record | string = state.t + let result: Record | string = state.translationData for (const k of keys) { if (typeof result === 'object' && result !== null && k in result) { diff --git a/deno.json b/deno.json index 26a6c2c..0a97462 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,6 @@ { "name": "@elsoul/fresh-i18n", - "version": "0.9.10", + "version": "0.9.11", "description": "A simple and flexible internationalization (i18n) plugin for Deno's Fresh framework.", "runtimes": ["deno", "browser"], "exports": "./mod.ts", diff --git a/mod.ts b/mod.ts index 8a28153..db4d83b 100644 --- a/mod.ts +++ b/mod.ts @@ -1,3 +1,4 @@ export { i18nPlugin } from '@/src/i18nPlugin.ts' +export { createTranslator } from '@/src/createTranslator.ts' export type { TranslationState } from '@/src/types.ts' diff --git a/src/createTranslator.ts b/src/createTranslator.ts new file mode 100644 index 0000000..b17400e --- /dev/null +++ b/src/createTranslator.ts @@ -0,0 +1,33 @@ +/** + * Retrieves a translation value from a nested translation object. + * + * @param translations - The translations object (e.g., ctx.state.translationData). + * @returns A function `t` that takes a translation key in dot notation and returns the translated string. + */ +export function createTranslator( + translations: Record>, +) { + /** + * Translates a key string like 'common.title' or 'common.titlerow.title.example' + * by traversing the nested structure of `translations`. + * + * @param key - The translation key in dot notation (e.g., 'common.title'). + * @returns The translated string, or an empty string if the key is not found. + */ + const t = (key: string): string => { + const keys = key.split('.') + let result: unknown = translations + + for (const k of keys) { + if (typeof result === 'object' && result !== null && k in result) { + result = (result as Record)[k] + } else { + return '' // Return empty string if key is not found + } + } + + return typeof result === 'string' ? result : '' + } + + return t +} diff --git a/src/i18nPlugin.ts b/src/i18nPlugin.ts index e7bb099..ea26904 100644 --- a/src/i18nPlugin.ts +++ b/src/i18nPlugin.ts @@ -29,31 +29,6 @@ async function readJsonFile(filePath: string): Promise> { } } -/** - * Retrieves a translation value from a nested translation object. - * - * @param translations - The translations object (e.g., ctx.state.translationData). - * @param key - The translation key in dot notation (e.g., 'common.title'). - * @returns The translated string, or an empty string if the key is not found. - */ -function getTranslation( - translations: Record, - key: string, -): string { - const keys = key.split('.') - let result: unknown = translations - - for (const k of keys) { - if (typeof result === 'object' && result !== null && k in result) { - result = (result as Record)[k] - } else { - return '' // Return empty string if key is not found - } - } - - return typeof result === 'string' ? result : '' -} - /** * Middleware function to initialize internationalization (i18n) support. * This plugin detects the user's language based on the URL, loads the necessary @@ -105,10 +80,7 @@ export const i18nPlugin = ( await loadTranslation(segment) } - // Set translationData and t function in ctx.state ctx.state.translationData = translationData - ctx.state.t = (key: string) => - getTranslation(ctx.state.translationData, key) const response = await ctx.next() as Response return response diff --git a/src/types.ts b/src/types.ts index 4789406..68d0986 100644 --- a/src/types.ts +++ b/src/types.ts @@ -4,13 +4,11 @@ * @property translationData - Object holding translation data for different namespaces. * @property path - The base path of the URL without the language prefix. * @property locale - The current locale code, used for translations. - * @property t - A function to get a translated string by key in dot notation. */ export interface TranslationState { translationData: Record> path: string locale: string - t: (key: string) => string // Function to retrieve translation string } /**