@stacksjs/i18n 0.70.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ var i=import.meta.require;function c(q,B){return r(B)(q)}function r(q){let B=q.split("-")[0].toLowerCase(),G=T[B];if(G)return G;return()=>"other"}function C(q,B="|"){let G=q.split(B).map((J)=>J.trim()),K=new Map;if(G.length===1)K.set("other",G[0]);else if(G.length===2)K.set("one",G[0]),K.set("other",G[1]);else if(G.length===3)K.set("zero",G[0]),K.set("one",G[1]),K.set("other",G[2]);else if(G.length>=4){let J=["zero","one","two","few","many","other"];for(let Q=0;Q<G.length&&Q<J.length;Q++)K.set(J[Q],G[Q])}return K}function O(q,B,G){let K=c(B,G);if(q.has(K))return q.get(K);if(q.has("other"))return q.get("other");let J=q.values().next();return J.done?"":J.value}var T={en:(q)=>q===1?"one":"other",de:(q)=>q===1?"one":"other",nl:(q)=>q===1?"one":"other",es:(q)=>q===1?"one":"other",it:(q)=>q===1?"one":"other",pt:(q)=>q===1?"one":"other",sv:(q)=>q===1?"one":"other",da:(q)=>q===1?"one":"other",no:(q)=>q===1?"one":"other",fi:(q)=>q===1?"one":"other",el:(q)=>q===1?"one":"other",he:(q)=>q===1?"one":"other",hu:(q)=>q===1?"one":"other",tr:(q)=>q===1?"one":"other",zh:()=>"other",ja:()=>"other",ko:()=>"other",vi:()=>"other",th:()=>"other",id:()=>"other",ms:()=>"other",fr:(q)=>q===0||q===1?"one":"other",ru:(q)=>{let B=q%10,G=q%100;if(B===1&&G!==11)return"one";if(B>=2&&B<=4&&(G<12||G>14))return"few";if(B===0||B>=5&&B<=9||G>=11&&G<=14)return"many";return"other"},uk:(q)=>{let B=q%10,G=q%100;if(B===1&&G!==11)return"one";if(B>=2&&B<=4&&(G<12||G>14))return"few";if(B===0||B>=5&&B<=9||G>=11&&G<=14)return"many";return"other"},pl:(q)=>{let B=q%10,G=q%100;if(q===1)return"one";if(B>=2&&B<=4&&(G<12||G>14))return"few";if(B===0||B===1||B>=5&&B<=9||G>=12&&G<=14)return"many";return"other"},cs:(q)=>{if(q===1)return"one";if(q>=2&&q<=4)return"few";return"other"},sk:(q)=>{if(q===1)return"one";if(q>=2&&q<=4)return"few";return"other"},ar:(q)=>{if(q===0)return"zero";if(q===1)return"one";if(q===2)return"two";let B=q%100;if(B>=3&&B<=10)return"few";if(B>=11&&B<=99)return"many";return"other"},cy:(q)=>{if(q===0)return"zero";if(q===1)return"one";if(q===2)return"two";if(q===3)return"few";if(q===6)return"many";return"other"},sl:(q)=>{let B=q%100;if(B===1)return"one";if(B===2)return"two";if(B===3||B===4)return"few";return"other"},ga:(q)=>{if(q===1)return"one";if(q===2)return"two";if(q>=3&&q<=6)return"few";if(q>=7&&q<=10)return"many";return"other"},lt:(q)=>{let B=q%10,G=q%100;if(B===1&&(G<11||G>19))return"one";if(B>=2&&B<=9&&(G<11||G>19))return"few";return"other"},lv:(q)=>{let B=q%10,G=q%100;if(q===0)return"zero";if(B===1&&G!==11)return"one";return"other"},ro:(q)=>{if(q===1)return"one";let B=q%100;if(q===0||B>=1&&B<=19)return"few";return"other"},hi:(q)=>q===0||q===1?"one":"other"};function Rq(){return Object.keys(T)}function Tq(q){return q.split("-")[0].toLowerCase()in T}function Fq(q,B){let G=q.split("-")[0].toLowerCase();T[G]=B}var v={locale:"en",fallbackLocale:"en",availableLocales:["en"],messages:{},warnMissing:!0,escapeValues:!1,keySeparator:".",pluralSeparator:"|"},Y="en",z="en",w={},H={...v};class j{_locale;_fallbackLocale;_messages;_config;constructor(q={}){this._config={...v,...q},this._locale=this._config.locale,this._fallbackLocale=this._config.fallbackLocale,this._messages=this._config.messages||{}}get locale(){return this._locale}set locale(q){this._locale=q}get fallbackLocale(){return this._fallbackLocale}get availableLocales(){return Object.keys(this._messages)}t=(q,B,G)=>{return this.translate(q,B,G)};tc=(q,B,G,K)=>{return this.translatePlural(q,B,G,K)};te=(q,B)=>{return this.hasTranslation(q,B)};tm=(q,B)=>{return this.getMessage(q,B)};setLocale=(q)=>{this._locale=q};addTranslations=(q,B)=>{if(!this._messages[q])this._messages[q]={};this._messages[q]=V(this._messages[q],B)};d=(q,B)=>{let G=typeof q==="number"?new Date(q):q,K=this._config.dateTimeFormats?.[this._locale]?.[B||"short"]||{};return new Intl.DateTimeFormat(this._locale,K).format(G)};n=(q,B)=>{let G=this._config.numberFormats?.[this._locale]?.[B||"decimal"]||{};return new Intl.NumberFormat(this._locale,G).format(q)};translate(q,B,G){let K=G||this._locale,J=this.getMessage(q,K);if(J===void 0){let Q=K.indexOf("-");if(Q>0){let X=K.slice(0,Q);if(X!==this._fallbackLocale)J=this.getMessage(q,X)}}if(J===void 0&&K!==this._fallbackLocale)J=this.getMessage(q,this._fallbackLocale);if(J===void 0){if(this._config.warnMissing)console.warn(`[i18n] Missing translation: "${q}" for locale "${K}"`);if(this._config.missingHandler){let Q=this._config.missingHandler(K,q);if(Q!==void 0)return Q}return q}if(typeof J!=="string")return q;return this.interpolate(J,B)}translatePlural(q,B,G,K){let J=K||this._locale,Q=this.getMessage(q,J);if(Q===void 0&&J!==this._fallbackLocale)Q=this.getMessage(q,this._fallbackLocale);if(Q===void 0||typeof Q!=="string"){if(this._config.warnMissing)console.warn(`[i18n] Missing plural translation: "${q}" for locale "${J}"`);return q}let X=C(Q,this._config.pluralSeparator),U=O(X,B,J),Z={count:B,n:B,...G};return this.interpolate(U,Z)}hasTranslation(q,B){let G=B||this._locale;return this.getMessage(q,G)!==void 0}getMessage(q,B){let G=this._messages[B];if(!G)return;let K=q.split(this._config.keySeparator||"."),J=G;for(let Q of K){if(J===void 0||typeof J==="string")return;J=J[Q]}return J}interpolate(q,B){if(!B)return q;return q.replace(/\{(\w+)\}/g,(G,K)=>{let J=B[K];if(J===void 0||J===null)return G;let Q=String(J);return this._config.escapeValues?qq(Q):Q})}}function n(q){Y=q}function _(){return Y}function Vq(q){z=q}function s(){return Object.keys(w)}function F(q,B){if(!w[q])w[q]={};w[q]=V(w[q],B)}function N(q){for(let[B,G]of Object.entries(q))F(B,G)}function L(q,B){return I(q,B||Y)!==void 0}function I(q,B){let G=w[B];if(!G)return;let K=q.split(H.keySeparator||"."),J=G;for(let Q of K){if(J===void 0||typeof J==="string")return;J=J[Q]}return J}function k(q,B){if(!B)return q;return q.replace(/\{(\w+)\}/g,(G,K)=>{let J=B[K];if(J===void 0||J===null)return G;return String(J)})}function f(q,B,G){let K=G||Y,J=I(q,K);if(J===void 0&&K!==z)J=I(q,z);if(J===void 0){if(H.warnMissing)console.warn(`[i18n] Missing translation: "${q}" for locale "${K}"`);return q}if(typeof J!=="string")return q;return k(J,B)}var t=f;function o(q,B,G,K){let J=K||Y,Q=I(q,J);if(Q===void 0&&J!==z)Q=I(q,z);if(Q===void 0||typeof Q!=="string")return q;let X=C(Q,H.pluralSeparator),U=O(X,B,J),Z={count:B,n:B,...G};return k(U,Z)}function l(q,B){return L(q,B)}function a(q,B){return I(q,B||Y)}function y(q={}){return new j(q)}function e(q={}){return y(q)}function Sq(q){if(H={...H,...q},q.locale)Y=q.locale;if(q.fallbackLocale)z=q.fallbackLocale;if(q.messages)N(q.messages)}function V(q,B){let G={...q};for(let K of Object.keys(B)){let J=B[K],Q=G[K];if(typeof J==="object"&&J!==null&&typeof Q==="object"&&Q!==null)G[K]=V(Q,J);else G[K]=J}return G}function qq(q){let B={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};return q.replace(/[&<>"']/g,(G)=>B[G]||G)}function Bq(q,B="medium",G){let K=G||_(),J=R(q),Q=typeof B==="string"?{dateStyle:B}:B;return new Intl.DateTimeFormat(K,Q).format(J)}function Gq(q,B="short",G){let K=G||_(),J=R(q),Q=typeof B==="string"?{timeStyle:B}:B;return new Intl.DateTimeFormat(K,Q).format(J)}function Jq(q,B="medium",G="short",K){let J=K||_(),Q=R(q);return new Intl.DateTimeFormat(J,{dateStyle:B,timeStyle:G}).format(Q)}function Kq(q,B=new Date,G="long",K){let J=K||_(),Q=R(q),X=R(B),U=Q.getTime()-X.getTime(),Z=Math.round(U/1000),$=Math.round(Z/60),A=Math.round($/60),E=Math.round(A/24),b=Math.round(E/7),h=Math.round(E/30),u=Math.round(E/365),W=new Intl.RelativeTimeFormat(J,{style:G});if(Math.abs(Z)<60)return W.format(Z,"second");if(Math.abs($)<60)return W.format($,"minute");if(Math.abs(A)<24)return W.format(A,"hour");if(Math.abs(E)<7)return W.format(E,"day");if(Math.abs(b)<4)return W.format(b,"week");if(Math.abs(h)<12)return W.format(h,"month");return W.format(u,"year")}function Qq(q,B={},G){let K=G||_(),J={...B};if(B.compact)J.notation="compact",J.compactDisplay="short";if(B.precision!==void 0)J.minimumFractionDigits=B.precision,J.maximumFractionDigits=B.precision;return new Intl.NumberFormat(K,J).format(q)}function Uq(q,B="USD",G={},K){let J=K||_();return new Intl.NumberFormat(J,{style:"currency",currency:B,...G}).format(q)}function Xq(q,B={},G){let K=G||_();return new Intl.NumberFormat(K,{style:"percent",...B}).format(q)}function Mq(q,B,G="short",K){let J=K||_();return new Intl.NumberFormat(J,{style:"unit",unit:B,unitDisplay:G}).format(q)}function Dq(q,B=2,G){let K=G||_();if(q===0)return"0 B";let J=1024,Q=["B","KB","MB","GB","TB","PB","EB","ZB","YB"],X=Math.floor(Math.log(q)/Math.log(J)),U=q/Math.pow(J,X);return`${new Intl.NumberFormat(K,{minimumFractionDigits:0,maximumFractionDigits:B}).format(U)} ${Q[X]}`}function Zq(q,B="conjunction",G="long",K){let J=K||_();return new Intl.ListFormat(J,{type:B,style:G}).format(q)}function p(q,B){let G=B||_();return new Intl.PluralRules(G).select(q)}function bq(q,B,G){let K=p(q,G);return B[K]??B.other}function S(q,B="language",G="long",K){let J=K||_();try{return new Intl.DisplayNames(J,{type:B,style:G}).of(q)}catch{return}}function hq(q,B){return S(q,"language","long",B)}function vq(q,B){return S(q,"region","long",B)}function Lq(q,B){return S(q,"currency","long",B)}function kq(q,B,G={},K){let J=K||_();return new Intl.Collator(J,G).compare(q,B)}function fq(q,B={},G){let K=G||_(),J=new Intl.Collator(K,B);return[...q].sort((Q,X)=>J.compare(Q,X))}function R(q){if(q instanceof Date)return q;if(typeof q==="number")return new Date(q);return new Date(q)}function _q(q){let G=(q||_()).split("-")[0].toLowerCase();return["ar","he","fa","ur","yi","ps","sd","ug","ku","ckb"].includes(G)?"rtl":"ltr"}function yq(q){return _q(q)==="rtl"}import{existsSync as $q,readdirSync as g}from"fs";import{readFile as Aq}from"fs/promises";import{basename as d,extname as P,join as x}from"path";import{log as Eq}from"@stacksjs/logging";async function Wq(q){let{directory:B,extensions:G=[".json",".yaml",".yml",".ts",".js"],recursive:K=!1,namespaceSeparator:J="."}=q,Q={};if(!$q(B))return Eq.warn(`[i18n] Translation directory not found: ${B}`),Q;return await m(B,Q,G,K,J,""),N(Q),Q}async function m(q,B,G,K,J,Q){let X=g(q,{withFileTypes:!0});for(let U of X){let Z=x(q,U.name);if(U.isDirectory()){let $=U.name;if(Iq($))await Yq(Z,$,B,G);else if(K){let A=Q?`${Q}${J}${U.name}`:U.name;await m(Z,B,G,K,J,A)}}else if(U.isFile()){let $=P(U.name);if(G.includes($)){let A=d(U.name,$);if(!B[A])B[A]={};let E=await M(Z);if(Q)Hq(B[A],Q,E,J);else B[A]=D(B[A],E)}}}}async function Yq(q,B,G,K){if(!G[B])G[B]={};let J=g(q,{withFileTypes:!0});for(let Q of J){if(!Q.isFile())continue;let X=P(Q.name);if(!K.includes(X))continue;let U=x(q,Q.name),Z=d(Q.name,X),$=await M(U);if(Z===B)G[B]=D(G[B],$);else G[B][Z]=$}}async function M(q){let B=P(q).toLowerCase(),G=await Aq(q,"utf8");switch(B){case".json":try{return JSON.parse(G)}catch{throw Error(`Invalid JSON in translation file: ${q}`)}case".yaml":case".yml":return zq(G);case".ts":case".js":{let K=await import(q);return K.default||K}default:throw Error(`Unsupported file type: ${B}`)}}async function wq(q,B){let G=await M(B);return F(q,G),G}function zq(q){try{let B=Bun.YAML.parse(q);if(!B||typeof B!=="object"||Array.isArray(B))throw Error("YAML content must be an object at the root level");return B}catch(B){let G=B instanceof Error?B.message:"Unknown YAML parse error";throw Error(`Invalid YAML translation file: ${G}`)}}function Iq(q){return/^[a-z]{2}(-[A-Z]{2})?(-[A-Za-z]+)?$/i.test(q)}function Hq(q,B,G,K){let J=B.split(K),Q=q;for(let U=0;U<J.length-1;U++){let Z=J[U];if(!Q[Z]||typeof Q[Z]==="string")Q[Z]={};Q=Q[Z]}let X=J[J.length-1];Q[X]=G}function D(q,B){let G={...q};for(let K of Object.keys(B)){let J=B[K],Q=G[K];if(typeof J==="object"&&J!==null&&typeof Q==="object"&&Q!==null)G[K]=D(Q,J);else G[K]=J}return G}function cq(q,B={}){return{load:()=>Wq({directory:q,...B}),loadLocale:(G,K)=>wq(G,x(q,K))}}async function rq(q){let{loadTranslations:B}=await import("@stacksjs/ts-i18n"),G=await B(q);return N(G),G}var sq={en:{code:"en",name:"English",nativeName:"English",direction:"ltr"},"en-US":{code:"en-US",name:"English (US)",nativeName:"English (US)",direction:"ltr",region:"US"},"en-GB":{code:"en-GB",name:"English (UK)",nativeName:"English (UK)",direction:"ltr",region:"GB"},es:{code:"es",name:"Spanish",nativeName:"Espa\xF1ol",direction:"ltr"},fr:{code:"fr",name:"French",nativeName:"Fran\xE7ais",direction:"ltr"},de:{code:"de",name:"German",nativeName:"Deutsch",direction:"ltr"},it:{code:"it",name:"Italian",nativeName:"Italiano",direction:"ltr"},pt:{code:"pt",name:"Portuguese",nativeName:"Portugu\xEAs",direction:"ltr"},"pt-BR":{code:"pt-BR",name:"Portuguese (Brazil)",nativeName:"Portugu\xEAs (Brasil)",direction:"ltr",region:"BR"},zh:{code:"zh",name:"Chinese",nativeName:"\u4E2D\u6587",direction:"ltr"},"zh-CN":{code:"zh-CN",name:"Chinese (Simplified)",nativeName:"\u7B80\u4F53\u4E2D\u6587",direction:"ltr",region:"CN"},"zh-TW":{code:"zh-TW",name:"Chinese (Traditional)",nativeName:"\u7E41\u9AD4\u4E2D\u6587",direction:"ltr",region:"TW"},ja:{code:"ja",name:"Japanese",nativeName:"\u65E5\u672C\u8A9E",direction:"ltr"},ko:{code:"ko",name:"Korean",nativeName:"\uD55C\uAD6D\uC5B4",direction:"ltr"},ar:{code:"ar",name:"Arabic",nativeName:"\u0627\u0644\u0639\u0631\u0628\u064A\u0629",direction:"rtl"},he:{code:"he",name:"Hebrew",nativeName:"\u05E2\u05D1\u05E8\u05D9\u05EA",direction:"rtl"},ru:{code:"ru",name:"Russian",nativeName:"\u0420\u0443\u0441\u0441\u043A\u0438\u0439",direction:"ltr"},nl:{code:"nl",name:"Dutch",nativeName:"Nederlands",direction:"ltr"},pl:{code:"pl",name:"Polish",nativeName:"Polski",direction:"ltr"},tr:{code:"tr",name:"Turkish",nativeName:"T\xFCrk\xE7e",direction:"ltr"},vi:{code:"vi",name:"Vietnamese",nativeName:"Ti\u1EBFng Vi\u1EC7t",direction:"ltr"},th:{code:"th",name:"Thai",nativeName:"\u0E44\u0E17\u0E22",direction:"ltr"},hi:{code:"hi",name:"Hindi",nativeName:"\u0939\u093F\u0928\u094D\u0926\u0940",direction:"ltr"}};import{loadTranslations as JB,generateTypes as KB,generateTypesFromModule as QB,generateSampleConfig as UB,writeOutputs as XB,createTranslator as ZB}from"@stacksjs/ts-i18n";export{XB as writeI18nOutputs,e as useI18n,t as trans,a as tm,l as te,o as tc,f as t,fq as sortStrings,n as setLocale,Vq as setFallbackLocale,O as selectPluralForm,bq as selectPlural,C as parsePluralForms,JB as loadTranslationsFromDisk,N as loadTranslations,wq as loadLocale,rq as loadFromTsI18n,Wq as loadFromDirectory,M as loadFile,yq as isRTL,L as hasTranslation,Tq as hasPluralRule,_q as getTextDirection,Rq as getSupportedPluralLocales,vq as getRegionName,r as getPluralRule,c as getPluralCategory,_ as getLocale,hq as getLanguageName,S as getDisplayName,Lq as getCurrencyName,s as getAvailableLocales,QB as generateI18nTypesFromModule,KB as generateI18nTypes,UB as generateI18nSampleConfig,Mq as formatUnit,Gq as formatTime,Kq as formatRelativeTime,p as formatPlural,Xq as formatPercent,Qq as formatNumber,Zq as formatList,Jq as formatDateTime,Bq as formatDate,Uq as formatCurrency,Dq as formatBytes,ZB as createSimpleTranslator,cq as createLoader,y as createI18n,Sq as configure,kq as compareStrings,F as addTranslations,Fq as addPluralRule,sq as LOCALE_INFO,j as I18n};
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Format a date
3
+ */
4
+ export declare function formatDate(date: Date | number | string, style?: DateStyle | DateFormatOptions, locale?: string): string;
5
+ /**
6
+ * Format a time
7
+ */
8
+ export declare function formatTime(date: Date | number | string, style?: TimeStyle | DateFormatOptions, locale?: string): string;
9
+ /**
10
+ * Format a date and time
11
+ */
12
+ export declare function formatDateTime(date: Date | number | string, dateStyle?: DateStyle, timeStyle?: TimeStyle, locale?: string): string;
13
+ /**
14
+ * Format relative time (e.g., "2 days ago", "in 3 hours")
15
+ */
16
+ export declare function formatRelativeTime(date: Date | number | string, baseDate?: Date | number | string, style?: 'long' | 'short' | 'narrow', locale?: string): string;
17
+ /**
18
+ * Format a number
19
+ */
20
+ export declare function formatNumber(value: number, options?: NumberFormatOptions, locale?: string): string;
21
+ /**
22
+ * Format a currency value
23
+ */
24
+ export declare function formatCurrency(value: number, currency?: string, options?: Omit<NumberFormatOptions, 'style' | 'currency'>, locale?: string): string;
25
+ /**
26
+ * Format a percentage
27
+ */
28
+ export declare function formatPercent(value: number, options?: Omit<NumberFormatOptions, 'style'>, locale?: string): string;
29
+ /**
30
+ * Format a number with units (e.g., "5 kilograms", "10 miles")
31
+ */
32
+ export declare function formatUnit(value: number, unit: string, unitDisplay?: 'long' | 'short' | 'narrow', locale?: string): string;
33
+ /**
34
+ * Format bytes to human-readable format
35
+ */
36
+ export declare function formatBytes(bytes: number, decimals?: number, locale?: string): string;
37
+ /**
38
+ * Format a list of items
39
+ */
40
+ export declare function formatList(items: string[], type?: ListType, style?: ListStyle, locale?: string): string;
41
+ /**
42
+ * Get the plural category for a number
43
+ */
44
+ export declare function formatPlural(value: number, locale?: string): Intl.LDMLPluralRule;
45
+ /**
46
+ * Select from plural options based on a number
47
+ */
48
+ export declare function selectPlural<T>(value: number, options: Partial<Record<Intl.LDMLPluralRule, T>> & { other: T }, locale?: string): T;
49
+ /**
50
+ * Get display name for a code
51
+ */
52
+ export declare function getDisplayName(code: string, type?: DisplayNameType, style?: 'long' | 'short' | 'narrow', locale?: string): string | undefined;
53
+ /**
54
+ * Get language name
55
+ */
56
+ export declare function getLanguageName(languageCode: string, locale?: string): string | undefined;
57
+ /**
58
+ * Get region/country name
59
+ */
60
+ export declare function getRegionName(regionCode: string, locale?: string): string | undefined;
61
+ /**
62
+ * Get currency name
63
+ */
64
+ export declare function getCurrencyName(currencyCode: string, locale?: string): string | undefined;
65
+ /**
66
+ * Compare strings in a locale-aware manner
67
+ */
68
+ export declare function compareStrings(a: string, b: string, options?: Intl.CollatorOptions, locale?: string): number;
69
+ /**
70
+ * Sort an array of strings in locale-aware order
71
+ */
72
+ export declare function sortStrings(strings: string[], options?: Intl.CollatorOptions, locale?: string): string[];
73
+ /**
74
+ * Get the text direction for a locale
75
+ */
76
+ export declare function getTextDirection(locale?: string): 'ltr' | 'rtl';
77
+ /**
78
+ * Check if a locale uses RTL text direction
79
+ */
80
+ export declare function isRTL(locale?: string): boolean;
81
+ export declare interface DateFormatOptions extends Intl.DateTimeFormatOptions {
82
+ dateStyle?: DateStyle
83
+ timeStyle?: TimeStyle
84
+ }
85
+ // =============================================================================
86
+ // Number Formatting
87
+ // =============================================================================
88
+ export declare interface NumberFormatOptions extends Intl.NumberFormatOptions {
89
+ compact?: boolean
90
+ precision?: number
91
+ }
92
+ // =============================================================================
93
+ // Date Formatting
94
+ // =============================================================================
95
+ export type DateStyle = 'full' | 'long' | 'medium' | 'short';
96
+ export type TimeStyle = 'full' | 'long' | 'medium' | 'short';
97
+ // =============================================================================
98
+ // List Formatting
99
+ // =============================================================================
100
+ export type ListType = 'conjunction' | 'disjunction' | 'unit';
101
+ export type ListStyle = 'long' | 'short' | 'narrow';
102
+ // =============================================================================
103
+ // Display Names
104
+ // =============================================================================
105
+ export type DisplayNameType = 'language' | 'region' | 'script' | 'currency' | 'calendar' | 'dateTimeField';
@@ -0,0 +1,83 @@
1
+ export type { I18nConfig as TsI18nConfig, TranslationTree, TranslationValue } from '@stacksjs/ts-i18n';
2
+ /**
3
+ * Stacks i18n - Internationalization System
4
+ *
5
+ * A comprehensive internationalization system with support for:
6
+ * - Translation loading from JSON/YAML files
7
+ * - Plural forms
8
+ * - Variable interpolation
9
+ * - Nested translations
10
+ * - Date/time formatting
11
+ * - Number formatting
12
+ * - Currency formatting
13
+ * - Relative time formatting
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { t, setLocale, addTranslations } from '@stacksjs/i18n'
18
+ *
19
+ * // Add translations
20
+ * addTranslations('en', {
21
+ * greeting: 'Hello, {name}!',
22
+ * items: '{count} item | {count} items',
23
+ * })
24
+ *
25
+ * // Use translations
26
+ * t('greeting', { name: 'World' }) // "Hello, World!"
27
+ * t('items', { count: 1 }) // "1 item"
28
+ * t('items', { count: 5 }) // "5 items"
29
+ *
30
+ * // Format dates and numbers
31
+ * formatDate(new Date(), 'long') // "January 8, 2026"
32
+ * formatNumber(1234567.89) // "1,234,567.89"
33
+ * formatCurrency(99.99, 'USD') // "$99.99"
34
+ * ```
35
+ */
36
+ export * from './translator';
37
+ export * from './formatter';
38
+ export * from './pluralization';
39
+ export * from './loader';
40
+ export * from './types';
41
+ // Re-export the file-loading and type-generation surface from
42
+ // `@stacksjs/ts-i18n`. The library handles disk loading (YAML / TS /
43
+ // JSON), namespace resolution, and `.d.ts` codegen for translation
44
+ // keys; the Stacks-side translator/formatter sits on top of that
45
+ // data with locale management, ICU pluralization, and Intl-backed
46
+ // formatters. Importing both names from `@stacksjs/i18n` keeps the
47
+ // app side from caring which symbol comes from which package.
48
+ export {
49
+ loadTranslations as loadTranslationsFromDisk,
50
+ generateTypes as generateI18nTypes,
51
+ generateTypesFromModule as generateI18nTypesFromModule,
52
+ generateSampleConfig as generateI18nSampleConfig,
53
+ writeOutputs as writeI18nOutputs,
54
+ createTranslator as createSimpleTranslator,
55
+ } from '@stacksjs/ts-i18n';
56
+ // Re-export main functions for convenience
57
+ export {
58
+ t,
59
+ trans,
60
+ tc,
61
+ te,
62
+ tm,
63
+ setLocale,
64
+ getLocale,
65
+ addTranslations,
66
+ loadTranslations,
67
+ getAvailableLocales,
68
+ hasTranslation,
69
+ I18n,
70
+ createI18n,
71
+ useI18n,
72
+ } from './translator';
73
+ export {
74
+ formatDate,
75
+ formatTime,
76
+ formatDateTime,
77
+ formatNumber,
78
+ formatCurrency,
79
+ formatPercent,
80
+ formatRelativeTime,
81
+ formatList,
82
+ formatPlural,
83
+ } from './formatter';
@@ -0,0 +1,49 @@
1
+ import type { TranslationMessages, Translations } from './types';
2
+ /**
3
+ * Load translations from a directory
4
+ */
5
+ export declare function loadFromDirectory(options: LoaderOptions): Promise<Translations>;
6
+ /**
7
+ * Load a single translation file
8
+ */
9
+ export declare function loadFile(filePath: string): Promise<TranslationMessages>;
10
+ /**
11
+ * Load a single locale from a file or directory
12
+ */
13
+ export declare function loadLocale(locale: string, path: string): Promise<TranslationMessages>;
14
+ /**
15
+ * Create a translation loader for a specific directory
16
+ */
17
+ export declare function createLoader(directory: string, options?: Partial<Omit<LoaderOptions, 'directory'>>): void;
18
+ /**
19
+ * Load translations via `@stacksjs/ts-i18n` and register them with the
20
+ * global translator. This is the recommended path for new projects —
21
+ * it gets you:
22
+ *
23
+ * - Per-locale subdirectory namespacing (en/auth.yaml → en.auth.*)
24
+ * - First-class .ts/.json/.yaml support with consistent error
25
+ * messages
26
+ * - Optional `.d.ts` codegen via `generateI18nTypes()` so message
27
+ * keys autocomplete in `t('…')` calls
28
+ *
29
+ * The legacy `loadFromDirectory()` remains for projects that depend
30
+ * on its specific behavior; new code should prefer this entry.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * await loadFromTsI18n({
35
+ * translationsDir: path.userI18nPath(),
36
+ * defaultLocale: 'en',
37
+ * fallbackLocale: 'en',
38
+ * sources: ['yaml', 'ts', 'json'],
39
+ * optional: true,
40
+ * })
41
+ * ```
42
+ */
43
+ export declare function loadFromTsI18n(config: import('@stacksjs/ts-i18n').I18nConfig): Promise<Translations>;
44
+ export declare interface LoaderOptions {
45
+ directory: string
46
+ extensions?: string[]
47
+ recursive?: boolean
48
+ namespaceSeparator?: string
49
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Get the plural category for a number in a given locale
3
+ */
4
+ export declare function getPluralCategory(n: number, locale: string): PluralCategory;
5
+ /**
6
+ * Get the plural rule function for a locale
7
+ */
8
+ export declare function getPluralRule(locale: string): PluralRule;
9
+ /**
10
+ * Parse a plural string into its forms
11
+ *
12
+ * Supports formats:
13
+ * - "one | other" (simple)
14
+ * - "zero | one | other" (with zero)
15
+ * - "{0} item | {0} items" (with placeholders)
16
+ * - "no items | one item | {n} items" (with special forms)
17
+ */
18
+ export declare function parsePluralForms(str: string, separator?: string): Map<PluralCategory, string>;
19
+ /**
20
+ * Select the appropriate plural form for a count
21
+ */
22
+ export declare function selectPluralForm(forms: Map<PluralCategory, string>, count: number, locale: string): string;
23
+ /**
24
+ * Get all supported locales for pluralization
25
+ */
26
+ export declare function getSupportedPluralLocales(): string[];
27
+ /**
28
+ * Check if a locale has custom plural rules
29
+ */
30
+ export declare function hasPluralRule(locale: string): boolean;
31
+ /**
32
+ * Add a custom plural rule for a locale
33
+ */
34
+ export declare function addPluralRule(locale: string, rule: PluralRule): void;
35
+ /**
36
+ * Pluralization Rules
37
+ *
38
+ * Implements CLDR plural rules for various languages.
39
+ * @see https://cldr.unicode.org/index/cldr-spec/plural-rules
40
+ */
41
+ export type PluralCategory = 'zero' | 'one' | 'two' | 'few' | 'many' | 'other';
42
+ export type PluralRule = (_n: number) => PluralCategory;
@@ -0,0 +1,79 @@
1
+ import type { I18nConfig, I18nInstance, InterpolationValues, TranslationMessages, Translations } from './types';
2
+ /**
3
+ * Set the current locale
4
+ */
5
+ export declare function setLocale(locale: string): void;
6
+ /**
7
+ * Get the current locale
8
+ */
9
+ export declare function getLocale(): string;
10
+ /**
11
+ * Set the fallback locale
12
+ */
13
+ export declare function setFallbackLocale(locale: string): void;
14
+ /**
15
+ * Get available locales
16
+ */
17
+ export declare function getAvailableLocales(): string[];
18
+ /**
19
+ * Add translations for a locale
20
+ */
21
+ export declare function addTranslations(locale: string, messages: TranslationMessages): void;
22
+ /**
23
+ * Load translations (alias for addTranslations for multiple locales)
24
+ */
25
+ export declare function loadTranslations(messages: Translations): void;
26
+ /**
27
+ * Check if a translation exists
28
+ */
29
+ export declare function hasTranslation(key: string, locale?: string): boolean;
30
+ /**
31
+ * Translate a key
32
+ */
33
+ export declare function t(key: string, values?: InterpolationValues, locale?: string): string;
34
+ /**
35
+ * Translate with pluralization
36
+ */
37
+ export declare function tc(key: string, count: number, values?: InterpolationValues, locale?: string): string;
38
+ /**
39
+ * Check if translation exists
40
+ */
41
+ export declare function te(key: string, locale?: string): boolean;
42
+ /**
43
+ * Get translation message object
44
+ */
45
+ export declare function tm(key: string, locale?: string): TranslationMessages | string | undefined;
46
+ /**
47
+ * Create a new i18n instance
48
+ */
49
+ export declare function createI18n(options?: Partial<I18nConfig>): I18n;
50
+ /**
51
+ * Use i18n composable (for Vue-like usage)
52
+ */
53
+ export declare function useI18n(options?: Partial<I18nConfig>): I18nInstance;
54
+ /**
55
+ * Configure the global i18n instance
56
+ */
57
+ export declare function configure(options: Partial<I18nConfig>): void;
58
+ /**
59
+ * Alias for t()
60
+ */
61
+ export declare const trans: unknown;
62
+ /**
63
+ * I18n class for creating isolated instances
64
+ */
65
+ export declare class I18n implements I18nInstance {
66
+ constructor(options?: Partial<I18nConfig>);
67
+ get locale(): string;
68
+ set locale(value: string);
69
+ get fallbackLocale(): string;
70
+ get availableLocales(): string[];
71
+ t: unknown;
72
+ tc: unknown;
73
+ te: unknown;
74
+ tm: unknown;
75
+ setLocale: unknown;
76
+ addTranslations: unknown;
77
+ d: unknown;
78
+ n: unknown;
79
+ }
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Common locales with metadata
3
+ */
4
+ export declare const LOCALE_INFO: {
5
+ en: {
6
+ code: 'en';
7
+ name: 'English';
8
+ nativeName: 'English';
9
+ direction: 'ltr'
10
+ };
11
+ 'en-US': {
12
+ code: 'en-US';
13
+ name: 'English (US)';
14
+ nativeName: 'English (US)';
15
+ direction: 'ltr';
16
+ region: 'US'
17
+ };
18
+ 'en-GB': {
19
+ code: 'en-GB';
20
+ name: 'English (UK)';
21
+ nativeName: 'English (UK)';
22
+ direction: 'ltr';
23
+ region: 'GB'
24
+ };
25
+ es: {
26
+ code: 'es';
27
+ name: 'Spanish';
28
+ nativeName: 'Espa\u00f1ol';
29
+ direction: 'ltr'
30
+ };
31
+ fr: {
32
+ code: 'fr';
33
+ name: 'French';
34
+ nativeName: 'Fran\u00e7ais';
35
+ direction: 'ltr'
36
+ };
37
+ de: {
38
+ code: 'de';
39
+ name: 'German';
40
+ nativeName: 'Deutsch';
41
+ direction: 'ltr'
42
+ };
43
+ it: {
44
+ code: 'it';
45
+ name: 'Italian';
46
+ nativeName: 'Italiano';
47
+ direction: 'ltr'
48
+ };
49
+ pt: {
50
+ code: 'pt';
51
+ name: 'Portuguese';
52
+ nativeName: 'Portugu\u00eas';
53
+ direction: 'ltr'
54
+ };
55
+ 'pt-BR': {
56
+ code: 'pt-BR';
57
+ name: 'Portuguese (Brazil)';
58
+ nativeName: 'Portugu\u00eas (Brasil)';
59
+ direction: 'ltr';
60
+ region: 'BR'
61
+ };
62
+ zh: {
63
+ code: 'zh';
64
+ name: 'Chinese';
65
+ nativeName: '\u4e2d\u6587';
66
+ direction: 'ltr'
67
+ };
68
+ 'zh-CN': {
69
+ code: 'zh-CN';
70
+ name: 'Chinese (Simplified)';
71
+ nativeName: '\u7b80\u4f53\u4e2d\u6587';
72
+ direction: 'ltr';
73
+ region: 'CN'
74
+ };
75
+ 'zh-TW': {
76
+ code: 'zh-TW';
77
+ name: 'Chinese (Traditional)';
78
+ nativeName: '\u7e41\u9ad4\u4e2d\u6587';
79
+ direction: 'ltr';
80
+ region: 'TW'
81
+ };
82
+ ja: {
83
+ code: 'ja';
84
+ name: 'Japanese';
85
+ nativeName: '\u65e5\u672c\u8a9e';
86
+ direction: 'ltr'
87
+ };
88
+ ko: {
89
+ code: 'ko';
90
+ name: 'Korean';
91
+ nativeName: '\ud55c\uad6d\uc5b4';
92
+ direction: 'ltr'
93
+ };
94
+ ar: {
95
+ code: 'ar';
96
+ name: 'Arabic';
97
+ nativeName: '\u0627\u0644\u0639\u0631\u0628\u064a\u0629';
98
+ direction: 'rtl'
99
+ };
100
+ he: {
101
+ code: 'he';
102
+ name: 'Hebrew';
103
+ nativeName: '\u05e2\u05d1\u05e8\u05d9\u05ea';
104
+ direction: 'rtl'
105
+ };
106
+ ru: {
107
+ code: 'ru';
108
+ name: 'Russian';
109
+ nativeName: '\u0420\u0443\u0441\u0441\u043a\u0438\u0439';
110
+ direction: 'ltr'
111
+ };
112
+ nl: {
113
+ code: 'nl';
114
+ name: 'Dutch';
115
+ nativeName: 'Nederlands';
116
+ direction: 'ltr'
117
+ };
118
+ pl: {
119
+ code: 'pl';
120
+ name: 'Polish';
121
+ nativeName: 'Polski';
122
+ direction: 'ltr'
123
+ };
124
+ tr: {
125
+ code: 'tr';
126
+ name: 'Turkish';
127
+ nativeName: 'T\u00fcrk\u00e7e';
128
+ direction: 'ltr'
129
+ };
130
+ vi: {
131
+ code: 'vi';
132
+ name: 'Vietnamese';
133
+ nativeName: 'Ti\u1ebfng Vi\u1ec7t';
134
+ direction: 'ltr'
135
+ };
136
+ th: {
137
+ code: 'th';
138
+ name: 'Thai';
139
+ nativeName: '\u0e44\u0e17\u0e22';
140
+ direction: 'ltr'
141
+ };
142
+ hi: {
143
+ code: 'hi';
144
+ name: 'Hindi';
145
+ nativeName: '\u0939\u093f\u0928\u094d\u0926\u0940';
146
+ direction: 'ltr'
147
+ }
148
+ };
149
+ /**
150
+ * Plural forms for a translation
151
+ */
152
+ export declare interface PluralForms {
153
+ zero?: string
154
+ one: string
155
+ two?: string
156
+ few?: string
157
+ many?: string
158
+ other: string
159
+ }
160
+ /**
161
+ * i18n configuration options
162
+ */
163
+ export declare interface I18nConfig {
164
+ locale: string
165
+ fallbackLocale: string
166
+ availableLocales?: string[]
167
+ messages?: Translations
168
+ missingHandler?: (locale: string, key: string) => string | undefined
169
+ warnMissing?: boolean
170
+ escapeValues?: boolean
171
+ keySeparator?: string
172
+ pluralSeparator?: string
173
+ dateTimeFormats?: DateTimeFormats
174
+ numberFormats?: NumberFormats
175
+ }
176
+ /**
177
+ * i18n instance interface
178
+ */
179
+ export declare interface I18nInstance {
180
+ locale: string
181
+ fallbackLocale: string
182
+ availableLocales: string[]
183
+ t: TranslateFunction
184
+ tc: TranslatePluralFunction
185
+ te: (key: string, locale?: string) => boolean
186
+ tm: (key: string, locale?: string) => TranslationMessages | string | undefined
187
+ setLocale: (locale: string) => void
188
+ addTranslations: (locale: string, messages: TranslationMessages) => void
189
+ d: (value: Date | number, format?: string) => string
190
+ n: (value: number, format?: string) => string
191
+ }
192
+ /**
193
+ * Locale metadata
194
+ */
195
+ export declare interface LocaleInfo {
196
+ code: string
197
+ name: string
198
+ nativeName: string
199
+ direction: 'ltr' | 'rtl'
200
+ region?: string
201
+ script?: string
202
+ }
203
+ /**
204
+ * i18n Type Definitions
205
+ */
206
+ /**
207
+ * Translation messages - can be nested objects or strings
208
+ */
209
+ export type TranslationMessages = {
210
+ [key: string]: string | TranslationMessages
211
+ }
212
+ /**
213
+ * All translations keyed by locale
214
+ */
215
+ export type Translations = {
216
+ [locale: string]: TranslationMessages
217
+ }
218
+ /**
219
+ * Interpolation values for translations
220
+ */
221
+ export type InterpolationValues = Record<string, string | number | boolean | null | undefined>;
222
+ /**
223
+ * Date/time format configurations per locale
224
+ */
225
+ export type DateTimeFormats = {
226
+ [locale: string]: {
227
+ [formatName: string]: Intl.DateTimeFormatOptions
228
+ }
229
+ }
230
+ /**
231
+ * Number format configurations per locale
232
+ */
233
+ export type NumberFormats = {
234
+ [locale: string]: {
235
+ [formatName: string]: Intl.NumberFormatOptions
236
+ }
237
+ }
238
+ /**
239
+ * Translation function
240
+ */
241
+ export type TranslateFunction = (
242
+ key: string,
243
+ values?: InterpolationValues,
244
+ locale?: string,
245
+ ) => string;
246
+ /**
247
+ * Plural translation function
248
+ */
249
+ export type TranslatePluralFunction = (
250
+ key: string,
251
+ count: number,
252
+ values?: InterpolationValues,
253
+ locale?: string,
254
+ ) => string;