@vocab/core
Advanced tools
Comparing version 0.0.10 to 0.0.11
# @vocab/core | ||
## 0.0.11 | ||
### Patch Changes | ||
- [`5b1fdc0`](https://github.com/seek-oss/vocab/commit/5b1fdc019522b12e7ef94b2fec57b54a9310d41c) [#46](https://github.com/seek-oss/vocab/pull/46) Thanks [@jahredhope](https://github.com/jahredhope)! - Enable the use of translation files directly with 3 new documented methods for working with translations. | ||
```typescript | ||
/** | ||
* Retrieve messages. If not available, will attempt to load messages and resolve once complete. | ||
*/ | ||
translations.getMessages(language); | ||
/** | ||
* Retrieve already loaded messages. Will return null if messages haven't been loaded. | ||
*/ | ||
translations.getLoadedMessages(language); | ||
/** | ||
* Load messages for the given language. Resolving once complete. | ||
*/ | ||
translations.load(language); | ||
``` | ||
- Updated dependencies [[`5b1fdc0`](https://github.com/seek-oss/vocab/commit/5b1fdc019522b12e7ef94b2fec57b54a9310d41c)]: | ||
- @vocab/types@0.0.9 | ||
## 0.0.10 | ||
@@ -4,0 +28,0 @@ |
import { TranslationModule, TranslationMessagesByKey } from '@vocab/types'; | ||
export { createTranslationFile } from './translation-file'; | ||
export declare const createLanguage: (module: TranslationMessagesByKey) => TranslationModule<any>; |
@@ -447,3 +447,2 @@ 'use strict'; | ||
translationKeyType.returnType = returnType; | ||
translationKeyType.message = 'string'; | ||
translationsType[key] = translationKeyType; | ||
@@ -453,9 +452,9 @@ } | ||
const content = Object.entries(loadedTranslation.languages).map(([languageName, translations]) => `"${languageName}": createLanguage(${JSON.stringify(getTranslationMessages(translations))})`).join(','); | ||
const languagesUnionAsString = Object.keys(loadedTranslation.languages).map(l => `'${l}'`).join(' | '); | ||
return `${banner} | ||
${Array.from(imports).join('\n')} | ||
import type { TranslationFile } from '@vocab/core'; | ||
import { createLanguage } from '@vocab/core/runtime'; | ||
import { createLanguage, createTranslationFile } from '@vocab/core/runtime'; | ||
const translations: TranslationFile<${serialiseObjectToType(translationsType)}> = {${content}}; | ||
const translations = createTranslationFile<${languagesUnionAsString}, ${serialiseObjectToType(translationsType)}>({${content}}); | ||
@@ -462,0 +461,0 @@ export default translations;`; |
@@ -447,3 +447,2 @@ 'use strict'; | ||
translationKeyType.returnType = returnType; | ||
translationKeyType.message = 'string'; | ||
translationsType[key] = translationKeyType; | ||
@@ -453,9 +452,9 @@ } | ||
const content = Object.entries(loadedTranslation.languages).map(([languageName, translations]) => `"${languageName}": createLanguage(${JSON.stringify(getTranslationMessages(translations))})`).join(','); | ||
const languagesUnionAsString = Object.keys(loadedTranslation.languages).map(l => `'${l}'`).join(' | '); | ||
return `${banner} | ||
${Array.from(imports).join('\n')} | ||
import type { TranslationFile } from '@vocab/core'; | ||
import { createLanguage } from '@vocab/core/runtime'; | ||
import { createLanguage, createTranslationFile } from '@vocab/core/runtime'; | ||
const translations: TranslationFile<${serialiseObjectToType(translationsType)}> = {${content}}; | ||
const translations = createTranslationFile<${languagesUnionAsString}, ${serialiseObjectToType(translationsType)}>({${content}}); | ||
@@ -462,0 +461,0 @@ export default translations;`; |
@@ -432,3 +432,2 @@ import { promises, existsSync } from 'fs'; | ||
translationKeyType.returnType = returnType; | ||
translationKeyType.message = 'string'; | ||
translationsType[key] = translationKeyType; | ||
@@ -438,9 +437,9 @@ } | ||
const content = Object.entries(loadedTranslation.languages).map(([languageName, translations]) => `"${languageName}": createLanguage(${JSON.stringify(getTranslationMessages(translations))})`).join(','); | ||
const languagesUnionAsString = Object.keys(loadedTranslation.languages).map(l => `'${l}'`).join(' | '); | ||
return `${banner} | ||
${Array.from(imports).join('\n')} | ||
import type { TranslationFile } from '@vocab/core'; | ||
import { createLanguage } from '@vocab/core/runtime'; | ||
import { createLanguage, createTranslationFile } from '@vocab/core/runtime'; | ||
const translations: TranslationFile<${serialiseObjectToType(translationsType)}> = {${content}}; | ||
const translations = createTranslationFile<${languagesUnionAsString}, ${serialiseObjectToType(translationsType)}>({${content}}); | ||
@@ -447,0 +446,0 @@ export default translations;`; |
@@ -22,3 +22,6 @@ 'use strict'; | ||
for (const translation of Object.keys(m)) { | ||
parsedICUMessages[translation] = new IntlMessageFormat__default['default'](m[translation], locale); | ||
const intlMessageFormat = new IntlMessageFormat__default['default'](m[translation], locale); | ||
parsedICUMessages[translation] = { | ||
format: params => intlMessageFormat.format(params) | ||
}; | ||
} | ||
@@ -25,0 +28,0 @@ |
@@ -22,3 +22,6 @@ 'use strict'; | ||
for (const translation of Object.keys(m)) { | ||
parsedICUMessages[translation] = new IntlMessageFormat__default['default'](m[translation], locale); | ||
const intlMessageFormat = new IntlMessageFormat__default['default'](m[translation], locale); | ||
parsedICUMessages[translation] = { | ||
format: params => intlMessageFormat.format(params) | ||
}; | ||
} | ||
@@ -25,0 +28,0 @@ |
@@ -14,3 +14,6 @@ import IntlMessageFormat from 'intl-messageformat'; | ||
for (const translation of Object.keys(m)) { | ||
parsedICUMessages[translation] = new IntlMessageFormat(m[translation], locale); | ||
const intlMessageFormat = new IntlMessageFormat(m[translation], locale); | ||
parsedICUMessages[translation] = { | ||
format: params => intlMessageFormat.format(params) | ||
}; | ||
} | ||
@@ -17,0 +20,0 @@ |
{ | ||
"name": "@vocab/core", | ||
"version": "0.0.10", | ||
"version": "0.0.11", | ||
"main": "dist/vocab-core.cjs.js", | ||
@@ -12,7 +12,8 @@ "module": "dist/vocab-core.esm.js", | ||
"runtime.ts", | ||
"icu-handler.ts" | ||
"icu-handler.ts", | ||
"translation-file.ts" | ||
] | ||
}, | ||
"dependencies": { | ||
"@vocab/types": "^0.0.8", | ||
"@vocab/types": "^0.0.9", | ||
"chalk": "^4.1.0", | ||
@@ -19,0 +20,0 @@ "chokidar": "^3.4.3", |
# Vocab | ||
Vocab is a strongly typed internationalisation framework for React. | ||
Vocab is a strongly typed internationalization framework for React. | ||
@@ -51,3 +51,3 @@ ## Getting started | ||
**Note:** Using methods discussed later we'll make sure the first language is loaded on page load. However, after this changing languages may then lead to a period of no translations as Vocab downloads the new language's translations. | ||
**Note:** Using methods discussed later we'll make sure the first language is loaded on page load. However, after this, changing languages may then lead to a period of no translations as Vocab downloads the new language's translations. | ||
@@ -104,3 +104,3 @@ **src/App.tsx** | ||
So far your app will run, but you're missing any translations other than the initial language. The below file can be created manually; however, you can also integrate with a remote translation platform to push and pull translations automatically. See [External translation tooling](#external-translation-tooling) for more information. | ||
So far, your app will run, but you're missing any translations other than the initial language. The below file can be created manually; however, you can also integrate with a remote translation platform to push and pull translations automatically. See [External translation tooling](#external-translation-tooling) for more information. | ||
@@ -113,3 +113,3 @@ **./example.vocab/fr-FR.translations.json** | ||
"message": "Bonjour de Vocab", | ||
"decription": "An optional description to help when translating" | ||
"description": "An optional description to help when translating" | ||
} | ||
@@ -125,3 +125,3 @@ } | ||
For example here is a Server Render function that would add the current language chunk to [Loadable component's ChunkExtractor](https://loadable-components.com/docs/api-loadable-server/#chunkextractor). | ||
For example, here is a Server Render function that would add the current language chunk to [Loadable component's ChunkExtractor](https://loadable-components.com/docs/api-loadable-server/#chunkextractor). | ||
@@ -142,2 +142,28 @@ **src/render.tsx** | ||
## ICU Message format | ||
Translation messages can sometimes contain dynamic values, such as dates/times, links or usernames. These values can often exist somewhere in the middle of a message and change location based on translation. | ||
To support this Vocab uses [Format.js's intl-messageformat] allowing you to use [ICU Message syntax](https://formatjs.io/docs/core-concepts/icu-syntax/) in your messages. | ||
In the below example we use two messages, one that passes in a single parameter and one uses a component. | ||
```json | ||
{ | ||
"my key with param": { | ||
"message": "Bonjour de {name}" | ||
}, | ||
"my key with component": { | ||
"message": "Bonjour de <Link>Vocab</Link>" | ||
} | ||
} | ||
``` | ||
Vocab will automatically parse these strings as ICU messages, identify the required parameters and ensure TypeScript knows the values must be passed in. | ||
```tsx | ||
t('my key with param', {name: 'Vocab'}); | ||
t('my key with component', {Link: children => (<a href="/foo">{children}</Link>)}); | ||
``` | ||
## Configuration | ||
@@ -175,2 +201,52 @@ | ||
## Use without React | ||
If you need to use Vocab outside of React, you can access the returned Vocab file directly. You'll then be responsible for when to load translations and how to update on translation load. | ||
#### Async access | ||
- `getMessages(language: string) => Promise<Messages>` returns messages for the given language formatted according to the correct locale. If the language has not been loaded it will load the language before resolving. | ||
**Note:** To optimize loading time you may want to call `load` (see below) ahead of use. | ||
#### Sync access | ||
- `load(language: string) => Promise<void>` attempts to pre-load messages for the given language. Resolving once complete. Note this only ensures the language is available and does not return any translations. | ||
- `getLoadedMessages(language: string) => Messages | null` returns messages for the given language formatted according to the correct locale. If the language has not been loaded it will return `null`. Note that this will not load the language if it's not available. Useful when a synchronous (non-promise) return is required. | ||
**Example: Promise based formatting of messages** | ||
```typescript | ||
import translations from './.vocab'; | ||
async function getFooMessage(language) { | ||
let messages = await translations.getMessages(language); | ||
return messages['my key'].format(); | ||
} | ||
getFooMessage().then((m) => console.log(m)); | ||
``` | ||
**Example: Synchronously returning a message** | ||
```typescript | ||
import translations from './.vocab'; | ||
function getFooMessageSync(language) { | ||
let messages = translations.getLoadedMessages(language); | ||
if (!messages) { | ||
// Translations not loaded, start loading and return null for now | ||
translations.load(); | ||
return null; | ||
} | ||
return messages.foo.format(); | ||
} | ||
translations.load(); | ||
const onClick = () => { | ||
console.log(getFooMessageSync()); | ||
}; | ||
``` | ||
## Generate Types | ||
@@ -194,3 +270,3 @@ | ||
Vocab can be used to syncronize your translations with translations from a remote translation platform. | ||
Vocab can be used to synchronize your translations with translations from a remote translation platform. | ||
@@ -206,4 +282,11 @@ | Platform | Environment Variables | | ||
## Troubleshooting | ||
### Problem: Passed locale is being ignored or using en-US instead | ||
When running in Node.js the locale formatting is supported by [Node.js's Internationalization support](https://nodejs.org/api/intl.html#intl_internationalization_support). Node.js will silently switch to the closest locale it can find if the passed locale is not available. | ||
See Node's documentation on [Options for building Node.js](https://nodejs.org/api/intl.html#intl_options_for_building_node_js) for information on ensuring Node has the locales you need. | ||
### License | ||
MIT. |
@@ -7,2 +7,3 @@ 'use strict'; | ||
var icuHandler_dist_vocabCoreIcuHandler = require('../../icu-handler/dist/vocab-core-icu-handler.cjs.dev.js'); | ||
var translationFile_dist_vocabCoreTranslationFile = require('../../translation-file/dist/vocab-core-translation-file.cjs.dev.js'); | ||
@@ -14,2 +15,3 @@ const createLanguage = module => ({ | ||
exports.createTranslationFile = translationFile_dist_vocabCoreTranslationFile.createTranslationFile; | ||
exports.createLanguage = createLanguage; |
@@ -7,2 +7,3 @@ 'use strict'; | ||
var icuHandler_dist_vocabCoreIcuHandler = require('../../icu-handler/dist/vocab-core-icu-handler.cjs.prod.js'); | ||
var translationFile_dist_vocabCoreTranslationFile = require('../../translation-file/dist/vocab-core-translation-file.cjs.prod.js'); | ||
@@ -14,2 +15,3 @@ const createLanguage = module => ({ | ||
exports.createTranslationFile = translationFile_dist_vocabCoreTranslationFile.createTranslationFile; | ||
exports.createLanguage = createLanguage; |
import 'intl-messageformat'; | ||
import { getParsedICUMessages } from '../../icu-handler/dist/vocab-core-icu-handler.esm.js'; | ||
export { createTranslationFile } from '../../translation-file/dist/vocab-core-translation-file.esm.js'; | ||
@@ -4,0 +5,0 @@ const createLanguage = module => ({ |
@@ -126,4 +126,2 @@ import { promises as fs, existsSync } from 'fs'; | ||
translationKeyType.message = 'string'; | ||
translationsType[key] = translationKeyType; | ||
@@ -141,11 +139,14 @@ } | ||
const languagesUnionAsString = Object.keys(loadedTranslation.languages) | ||
.map((l) => `'${l}'`) | ||
.join(' | '); | ||
return `${banner} | ||
${Array.from(imports).join('\n')} | ||
import type { TranslationFile } from '@vocab/core'; | ||
import { createLanguage } from '@vocab/core/runtime'; | ||
import { createLanguage, createTranslationFile } from '@vocab/core/runtime'; | ||
const translations: TranslationFile<${serialiseObjectToType( | ||
const translations = createTranslationFile<${languagesUnionAsString}, ${serialiseObjectToType( | ||
translationsType, | ||
)}> = {${content}}; | ||
)}>({${content}}); | ||
@@ -152,0 +153,0 @@ export default translations;`; |
@@ -26,6 +26,6 @@ import { ParsedICUMessages, TranslationMessagesByKey } from '@vocab/types'; | ||
for (const translation of Object.keys(m)) { | ||
parsedICUMessages[translation] = new IntlMessageFormat( | ||
m[translation], | ||
locale, | ||
); | ||
const intlMessageFormat = new IntlMessageFormat(m[translation], locale); | ||
parsedICUMessages[translation] = { | ||
format: (params: any) => intlMessageFormat.format(params), | ||
}; | ||
} | ||
@@ -32,0 +32,0 @@ |
@@ -5,2 +5,4 @@ import { TranslationModule, TranslationMessagesByKey } from '@vocab/types'; | ||
export { createTranslationFile } from './translation-file'; | ||
export const createLanguage = ( | ||
@@ -7,0 +9,0 @@ module: TranslationMessagesByKey, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
143187
52
3425
285
17
+ Added@vocab/types@0.0.9(transitive)
- Removed@vocab/types@0.0.8(transitive)
Updated@vocab/types@^0.0.9