@payloadcms/translations
Advanced tools
Comparing version 3.0.0-alpha.60 to 3.0.0-alpha.61
@@ -0,3 +1,5 @@ | ||
export { importDateFNSLocale } from '../importDateFNSLocale.js' | ||
export { getTranslation } from '../utilities/getTranslation.js' | ||
export { initI18n, matchLanguage, t } from '../utilities/init.js' | ||
export { initI18n, t } from '../utilities/init.js' | ||
export { acceptedLanguages, matchLanguage, rtlLanguages } from '../utilities/languages.js' | ||
export type * from '../types.js' |
@@ -0,4 +1,6 @@ | ||
export { importDateFNSLocale } from '../importDateFNSLocale.js'; | ||
export { getTranslation } from '../utilities/getTranslation.js'; | ||
export { initI18n, matchLanguage, t } from '../utilities/init.js'; | ||
export { initI18n, t } from '../utilities/init.js'; | ||
export { acceptedLanguages, matchLanguage, rtlLanguages } from '../utilities/languages.js'; | ||
export type * from '../types.js'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -0,3 +1,5 @@ | ||
export { importDateFNSLocale } from '../importDateFNSLocale.js'; | ||
export { getTranslation } from '../utilities/getTranslation.js'; | ||
export { initI18n, matchLanguage, t } from '../utilities/init.js'; | ||
export { initI18n, t } from '../utilities/init.js'; | ||
export { acceptedLanguages, matchLanguage, rtlLanguages } from '../utilities/languages.js'; | ||
//# sourceMappingURL=index.js.map |
@@ -1,11 +0,21 @@ | ||
export type LanguageTranslations = { | ||
[namespace: string]: { | ||
[key: string]: string; | ||
import type { Locale } from 'date-fns'; | ||
import type { acceptedLanguages } from './utilities/languages.js'; | ||
type DateFNSKeys = 'ar' | 'az' | 'bg' | 'cs' | 'de' | 'en-US' | 'es' | 'fa-IR' | 'fr' | 'hr' | 'hu' | 'it' | 'ja' | 'ko' | 'nb' | 'nl' | 'pl' | 'pt' | 'ro' | 'ru' | 'sv' | 'th' | 'tr' | 'vi' | 'zh-CN' | 'zh-TW'; | ||
export type Language = { | ||
dateFNSKey: DateFNSKeys; | ||
translations: { | ||
[namespace: string]: { | ||
[key: string]: string; | ||
}; | ||
}; | ||
}; | ||
export type Translations = { | ||
[language: string]: LanguageTranslations; | ||
export type AcceptedLanguages = (typeof acceptedLanguages)[number]; | ||
export type SupportedLanguages = { | ||
[key in AcceptedLanguages]?: Language; | ||
}; | ||
export type TFunction = (key: string, options?: Record<string, any>) => string; | ||
export type I18n = { | ||
dateFNS: Locale; | ||
/** Corresponding dateFNS key */ | ||
dateFNSKey: DateFNSKeys; | ||
/** The fallback language */ | ||
@@ -16,13 +26,11 @@ fallbackLanguage: string; | ||
/** Translate function */ | ||
t: (key: string, options?: Record<string, unknown>) => string; | ||
translations: Translations; | ||
t: TFunction; | ||
translations: Language['translations']; | ||
}; | ||
export type I18nOptions = { | ||
fallbackLanguage?: string; | ||
supportedLanguages?: string[]; | ||
translations?: { | ||
[language: string]: { | ||
$schema: string; | ||
} | LanguageTranslations; | ||
}; | ||
supportedLanguages?: SupportedLanguages; | ||
translations?: Partial<{ | ||
[key in AcceptedLanguages]?: Language['translations']; | ||
}>; | ||
}; | ||
@@ -32,6 +40,6 @@ export type InitTFunction = (args: { | ||
language?: string; | ||
translations?: Translations; | ||
translations: Language['translations']; | ||
}) => { | ||
t: TFunction; | ||
translations: Translations; | ||
translations: Language['translations']; | ||
}; | ||
@@ -41,5 +49,9 @@ export type InitI18n = (args: { | ||
context: 'api' | 'client'; | ||
language?: string; | ||
translations: Translations; | ||
}) => I18n; | ||
language?: AcceptedLanguages; | ||
}) => Promise<I18n>; | ||
export type LanguagePreference = { | ||
language: AcceptedLanguages; | ||
quality?: number; | ||
}; | ||
export {}; | ||
//# sourceMappingURL=types.d.ts.map |
import type { JSX } from 'react'; | ||
import type { I18n } from '../types.js'; | ||
type LabelType = JSX.Element | Record<string, string> | string; | ||
export declare const getTranslation: <T extends LabelType>(label: T, i18n: Pick<I18n, 'fallbackLanguage' | 'language'>) => T extends JSX.Element ? JSX.Element : string; | ||
import type { I18n, TFunction } from '../types.js'; | ||
type LabelType = (({ t }: { | ||
t: TFunction; | ||
}) => string) | JSX.Element | Record<string, string> | string; | ||
export declare const getTranslation: <T extends LabelType>(label: T, i18n: Pick<I18n, 'fallbackLanguage' | 'language' | 't'>) => T extends JSX.Element ? JSX.Element : string; | ||
export {}; | ||
//# sourceMappingURL=getTranslation.d.ts.map |
@@ -17,2 +17,5 @@ export const getTranslation = (label, i18n) => { | ||
} | ||
if (typeof label === 'function') { | ||
return label({ t: i18n.t }); | ||
} | ||
// If it's a React Element or string, then we should just pass it through | ||
@@ -19,0 +22,0 @@ return label; |
@@ -1,2 +0,2 @@ | ||
import type { InitI18n, Translations } from '../types.js'; | ||
import type { InitI18n, Language } from '../types.js'; | ||
/** | ||
@@ -12,3 +12,3 @@ * @function getTranslationString | ||
key: string; | ||
translations: Translations[0]; | ||
translations: Language['translations']; | ||
}) => string; | ||
@@ -25,9 +25,8 @@ /** | ||
key: string; | ||
translations?: Translations[0]; | ||
translations?: Language['translations']; | ||
vars?: Record<string, any>; | ||
}) => string; | ||
export declare const t: TFunctionConstructor; | ||
export declare function matchLanguage(header: string): string | undefined; | ||
export declare const initI18n: InitI18n; | ||
export {}; | ||
//# sourceMappingURL=init.d.ts.map |
@@ -0,2 +1,4 @@ | ||
import { importDateFNSLocale } from '../importDateFNSLocale.js'; | ||
import { deepMerge } from './deepMerge.js'; | ||
import { getTranslationsByContext } from './getTranslationsByContext.js'; | ||
/** | ||
@@ -88,61 +90,5 @@ * @function getTranslationString | ||
}; | ||
function parseAcceptLanguage(header) { | ||
return header | ||
.split(',') | ||
.map((lang) => { | ||
const [language, quality] = lang.trim().split(';q='); | ||
return { | ||
language, | ||
quality: quality ? parseFloat(quality) : 1, | ||
}; | ||
}) | ||
.sort((a, b) => b.quality - a.quality); // Sort by quality, highest to lowest | ||
} | ||
const acceptedLanguages = [ | ||
'ar', | ||
'az', | ||
'bg', | ||
'cs', | ||
'de', | ||
'en', | ||
'es', | ||
'fa', | ||
'fr', | ||
'hr', | ||
'hu', | ||
'it', | ||
'ja', | ||
'ko', | ||
'my', | ||
'nb', | ||
'nl', | ||
'pl', | ||
'pt', | ||
'ro', | ||
'rs', | ||
'rsLatin', | ||
'ru', | ||
'sv', | ||
'th', | ||
'tr', | ||
'ua', | ||
'vi', | ||
'zh', | ||
'zhTw', | ||
]; | ||
export function matchLanguage(header) { | ||
const parsedHeader = parseAcceptLanguage(header); | ||
for (const { language } of parsedHeader) { | ||
for (const acceptedLanguage of acceptedLanguages) { | ||
if (language.startsWith(acceptedLanguage)) { | ||
return acceptedLanguage; | ||
} | ||
} | ||
} | ||
return undefined; | ||
} | ||
const initTFunction = (args) => { | ||
const { config, language, translations } = args; | ||
const mergedTranslations = deepMerge(config?.translations ?? {}, translations); | ||
const languagePreference = matchLanguage(language); | ||
const mergedTranslations = deepMerge(translations, config?.translations?.[language] ?? {}); | ||
return { | ||
@@ -152,3 +98,3 @@ t: (key, vars) => { | ||
key, | ||
translations: mergedTranslations[languagePreference], | ||
translations: mergedTranslations, | ||
vars, | ||
@@ -162,6 +108,6 @@ }); | ||
const cacheMap = new Map(); | ||
const memoized = (args) => { | ||
const memoized = async (args) => { | ||
const cacheKey = keys.reduce((acc, key) => acc + args[key], ''); | ||
if (!cacheMap.has(cacheKey)) { | ||
const result = fn(args); | ||
const result = await fn(args); | ||
cacheMap.set(cacheKey, result); | ||
@@ -173,13 +119,18 @@ } | ||
} | ||
export const initI18n = memoize(({ config, language = 'en', translations: incomingTranslations }) => { | ||
const { t, translations } = initTFunction({ | ||
export const initI18n = memoize(async ({ config, context, language = 'en' }) => { | ||
const translations = getTranslationsByContext(config.supportedLanguages[language], context); | ||
const { t, translations: mergedTranslations } = initTFunction({ | ||
config, | ||
language: language || config.fallbackLanguage, | ||
translations: incomingTranslations, | ||
translations, | ||
}); | ||
const dateFNSKey = config.supportedLanguages[language]?.dateFNSKey || 'en-US'; | ||
const dateFNS = await importDateFNSLocale(dateFNSKey); | ||
const i18n = { | ||
dateFNS, | ||
dateFNSKey, | ||
fallbackLanguage: config.fallbackLanguage, | ||
language: language || config.fallbackLanguage, | ||
t, | ||
translations, | ||
translations: mergedTranslations, | ||
}; | ||
@@ -186,0 +137,0 @@ return i18n; |
{ | ||
"name": "@payloadcms/translations", | ||
"version": "3.0.0-alpha.60", | ||
"version": "3.0.0-alpha.61", | ||
"main": "./dist/exports/index.js", | ||
@@ -19,11 +19,11 @@ "types": "./dist/exports/index.d.ts", | ||
}, | ||
"./api": { | ||
"import": "./dist/_generatedFiles_/api/index.js", | ||
"require": "./dist/_generatedFiles_/api/index.js", | ||
"types": "./dist/_generatedFiles_/exports/*.d.ts" | ||
"./*": { | ||
"import": "./dist/exports/*.js", | ||
"require": "./dist/exports/*.js", | ||
"types": "./dist/exports/*.d.ts" | ||
}, | ||
"./client": { | ||
"import": "./dist/_generatedFiles_/client/index.js", | ||
"require": "./dist/_generatedFiles_/client/index.js", | ||
"types": "./dist/_generatedFiles_/exports/*.d.ts" | ||
"./languages/*": { | ||
"import": "./dist/languages/*.js", | ||
"require": "./dist/languages/*.js", | ||
"types": "./dist/languages/*.d.ts" | ||
} | ||
@@ -37,2 +37,3 @@ }, | ||
"@types/react": "18.2.74", | ||
"date-fns": "3.3.1", | ||
"typescript": "5.4.4", | ||
@@ -46,6 +47,5 @@ "@payloadcms/eslint-config": "1.1.1" | ||
"build:types": "tsc --outDir dist", | ||
"build": "pnpm writeFiles && pnpm build:types", | ||
"clean": "rimraf {dist,*.tsbuildinfo}", | ||
"writeFiles": "npx tsx ./writeTranslationFiles.ts" | ||
"build": "pnpm build:types", | ||
"clean": "rimraf {dist,*.tsbuildinfo}" | ||
} | ||
} |
118
README.md
@@ -46,1 +46,119 @@ # Payload Translations | ||
``` | ||
Here is a full list of language keys. Note that these are not all implemented, but if you would like to contribute and add a new language, you can use this list as a reference: | ||
| Language Code | Language Name | | ||
| -------------- | ------------------------------------------ | | ||
| af | Afrikaans | | ||
| am | Amharic | | ||
| ar-sa | Arabic (Saudi Arabia) | | ||
| as | Assamese | | ||
| az-Latn | Azerbaijani (Latin) | | ||
| be | Belarusian | | ||
| bg | Bulgarian | | ||
| bn-BD | Bangla (Bangladesh) | | ||
| bn-IN | Bangla (India) | | ||
| bs | Bosnian (Latin) | | ||
| ca | Catalan Spanish | | ||
| ca-ES-valencia | Valencian | | ||
| cs | Czech | | ||
| cy | Welsh | | ||
| da | Danish | | ||
| de | German (Germany) | | ||
| el | Greek | | ||
| en-GB | English (United Kingdom) | | ||
| en-US | English (United States) | | ||
| es | Spanish (Spain) | | ||
| es-ES | Spanish (Spain) | | ||
| es-US | Spanish (United States) | | ||
| es-MX | Spanish (Mexico) | | ||
| et | Estonian | | ||
| eu | Basque | | ||
| fa | Persian | | ||
| fi | Finnish | | ||
| fil-Latn | Filipino | | ||
| fr | French (France) | | ||
| fr-FR | French (France) | | ||
| fr-CA | French (Canada) | | ||
| ga | Irish | | ||
| gd-Latn | Scottish Gaelic | | ||
| gl | Galician | | ||
| gu | Gujarati | | ||
| ha-Latn | Hausa (Latin) | | ||
| he | Hebrew | | ||
| hi | Hindi | | ||
| hr | Croatian | | ||
| hu | Hungarian | | ||
| hy | Armenian | | ||
| id | Indonesian | | ||
| ig-Latn | Igbo | | ||
| is | Icelandic | | ||
| it | Italian (Italy) | | ||
| it-it | Italian (Italy) | | ||
| ja | Japanese | | ||
| ka | Georgian | | ||
| kk | Kazakh | | ||
| km | Khmer | | ||
| kn | Kannada | | ||
| ko | Korean | | ||
| kok | Konkani | | ||
| ku-Arab | Central Kurdish | | ||
| ky-Cyrl | Kyrgyz | | ||
| lb | Luxembourgish | | ||
| lt | Lithuanian | | ||
| lv | Latvian | | ||
| mi-Latn | Maori | | ||
| mk | Macedonian | | ||
| ml | Malayalam | | ||
| mn-Cyrl | Mongolian (Cyrillic) | | ||
| mr | Marathi | | ||
| ms | Malay (Malaysia) | | ||
| mt | Maltese | | ||
| nb | Norwegian (Bokmål) | | ||
| ne | Nepali (Nepal) | | ||
| nl | Dutch (Netherlands) | | ||
| nl-BE | Dutch (Netherlands) | | ||
| nn | Norwegian (Nynorsk) | | ||
| nso | Sesotho sa Leboa | | ||
| or | Odia | | ||
| pa | Punjabi (Gurmukhi) | | ||
| pa-Arab | Punjabi (Arabic) | | ||
| pl | Polish | | ||
| prs-Arab | Dari | | ||
| pt-BR | Portuguese (Brazil) | | ||
| pt-PT | Portuguese (Portugal) | | ||
| qut-Latn | K’iche’ | | ||
| quz | Quechua (Peru) | | ||
| ro | Romanian (Romania) | | ||
| ru | Russian | | ||
| rw | Kinyarwanda | | ||
| sd-Arab | Sindhi (Arabic) | | ||
| si | Sinhala | | ||
| sk | Slovak | | ||
| sl | Slovenian | | ||
| sq | Albanian | | ||
| sr-Cyrl-BA | Serbian (Cyrillic, Bosnia and Herzegovina) | | ||
| sr-Cyrl-RS | Serbian (Cyrillic, Serbia) | | ||
| sr-Latn-RS | Serbian (Latin, Serbia) | | ||
| sv | Swedish (Sweden) | | ||
| sw | Kiswahili | | ||
| ta | Tamil | | ||
| te | Telugu | | ||
| tg-Cyrl | Tajik (Cyrillic) | | ||
| th | Thai | | ||
| ti | Tigrinya | | ||
| tk-Latn | Turkmen (Latin) | | ||
| tn | Setswana | | ||
| tr | Turkish | | ||
| tt-Cyrl | Tatar (Cyrillic) | | ||
| ug-Arab | Uyghur | | ||
| uk | Ukrainian | | ||
| ur | Urdu | | ||
| uz-Latn | Uzbek (Latin) | | ||
| vi | Vietnamese | | ||
| wo | Wolof | | ||
| xh | isiXhosa | | ||
| yo-Latn | Yoruba | | ||
| zh-Hans | Chinese (Simplified) | | ||
| zh-Hant | Chinese (Traditional) | | ||
| zu | isiZulu | |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
164
1021749
5
171
12306
1