Skip to content

Commit

Permalink
Merge pull request #2 from sveyret/preferences
Browse files Browse the repository at this point in the history
Add access to preferences
  • Loading branch information
sveyret authored May 7, 2018
2 parents da06465 + f796b0a commit 5d250f5
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 25 deletions.
24 changes: 14 additions & 10 deletions doc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,29 @@ This interface describes how objects containing messages for a given language sh

Do not type your default language with `Message`, because if you do so, `typeof` will return `Message` and you will loose the specific type checking of your messages. If your default language is not written as expected, a compile time error will be raised when the language map will be created.

# LanguageMapDefinition<T extends Messages>
# LanguageMapDefinition\<T extends Messages>

This interface describes the data of a full language map. It may be used to retrieve a serialized language map, for exemple when a language map is transmitted from server to browser (see [code snippets](./examples.md)).

The generic parameter `T` represents the type of the default language.

Note that the `Intl` class converts language code to lowercase and digit separated with underscores. So, instead of, for example `no-NO-NY`, you should use `no_no_ny` in the language map definition key.

# LanguageMap<T extends Messages>
# LanguageMap\<T extends Messages>

This object is containing the language map, i.e. the default language messages and all translations for all languages.

The generic parameter `T` represents the type of the default language.

## constructor(messages: LanguageMapDefinition<T>)
## constructor(messages: LanguageMapDefinition\<T>)

Create a language map based on a definition (an object containing all language map data, including default language).

## constructor(messages: T, defaultLang?: string)

Create a language map base on the default messages. If the `defaultLang` parameter is given, the default messages will also be used for language corresponding to the given name. This may be useful for the default language to be listed in available languages.

## merge(additional: { [key: string]: Partial<Messages> }): LanguageMap<T>
## merge(additional: { [key: string]: Partial\<Messages> }): LanguageMap\<T>

Create a new language map containing given messages merged to current definition. The `additional` parameter may replace existing strings, create new languages or even extend the string list (e.g. plugin specific messages).

Expand All @@ -38,7 +38,7 @@ Indicate if the language map contains the given language. This cannot be used to

Give the list of available languages. These are the languages which would return true if tested with `contains`. This parameter is read-only.

## messages(lang?: string): T | Partial<T>
## messages(lang?: string): T | Partial\<T>

Give all the messages for the given language code. If the language is not available or if the parameter `lang` is not provided, this will return default language messages.

Expand All @@ -50,27 +50,31 @@ Give all the messages for the default language. This parameter is read-only.

Give a JavaScript string which is a serialization of the language map. This parameter is read-only.

# Intl<T extends Messages>
# Intl\<T extends Messages>

This class is managing the internationalization object. It is based on a language map and language preferences.

The generic parameter `T` represents the type of the default language.

## constructor(languages: LanguageMap<T>, preferences?: ReadonlyArray<string>, createGeneric: boolean = true)
## constructor(languages: LanguageMap\<T>, preferences?: ReadonlyArray\<string>, createGeneric: boolean = true)

Create an internationalization object using the given language map. If `preferences` parameter is provided, its value will be used as the user preferred language order. If true, the parameter `createGeneric` allow more generic language codes to be automatically added in preferences. For example, if preference contains `no-NO-NY`, it will automatically add `no-NO` and `no` in this order after this entry. This parameter may be set to false, for example when using browser preferred languages, as end-user may already define specific and generic preferences.

Note that language code are formatted to lowercase and digit separated with underscores. So, instead of `no-NO-NY`, the actual language code will be `no_no_ny`. This will ensure a single way of writting language codes, using characters which are valid as object keys in TypeScript (preventing the need to use quotes).

## changePreferences(preferences: ReadonlyArray<string>, createGeneric: boolean = true): Intl<T>
## changePreferences(preferences: ReadonlyArray\<string>, createGeneric: boolean = true): Intl\<T>

Create a new internationalization object with the same language map as this one but new preferences.

## t<K extends keyof T>(name: K, ...args: any[]): string
## preferences: ReadonlyArray\<string>

The preferences really used by the object. Only languages which are found in the language map are retained.

## t\<K extends keyof T>(name: K, ...args: any[]): string

Build the message for the given name with given parameters in the most appropriate language. This method is actually overridden so that parameter types are checked at compile time against message expected parameter types.

## getMessage<K extends keyof T>(name: K): T[K]
## getMessage\<K extends keyof T>(name: K): T[K]

Get the message corresponding to the given name in the most appropriate language. The message is not formatted and may be a string or a function.

Expand Down
26 changes: 15 additions & 11 deletions doc/fr/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,29 @@ Cette interface décrit comment écrire les objets contenant les messages pour u

Ne typez pas votre langue par défaut avec `Message`, car dans ce cas, `typeof` retournera `Message` et vous perdrez la vérification spécifique de vos messages. Si la langue par défaut n'est pas écrite comme attendu, une erreur de compilation sera levée lorsque la table de langues sera créée.

# LanguageMapDefinition<T extends Messages>
# LanguageMapDefinition\<T extends Messages>

Cette interface décrit les données d'une table de langues complète. Elle peut être utilisée pour récupérer une table de langues sérialisée, par exemple, lorsqu'une table de langue est transmise par un serveur à un navigateur (cf. [exemples de code](./examples.md)).

Le paramètre générique `T` représente le type de la langue par défaut.

Notez que la classe `Intl` convertie les code de langue en caractères minuscules et chiffres séparés par des soulignés. Cela signifie que, par exemple, au lieu d'utiliser `no-NO-NY`, vous devriez utiliser `no_no_ny` dans les clés des tables de langues.

# LanguageMap<T extends Messages>
# LanguageMap\<T extends Messages>

Cette objet contient la table de langues, c'est-à-dire la langue par défaut et toutes les traductions pour toutes les langues.

Le paramètre générique `T` représente le type de la langue par défaut.

## constructor(messages: LanguageMapDefinition<T>)
## constructor(messages: LanguageMapDefinition\<T>)

Créer une table de langues basée sur une définition (un objet contenant toutes les données de la table de langues, y compris la langue par défaut).

## constructor(messages: T, defaultLang?: string)

Créer une table de langue basée sur les messages par défaut. Si le paramètre `defaultLang` est fourni, les messages par défaut seront également utilisés pour la langue correspondant au nom donné. Cela peut être utile pour que la langue par défaut soit listée parmi les langues disponibles.

## merge(additional: { [key: string]: Partial<Messages> }): LanguageMap<T>
## merge(additional: { [key: string]: Partial\<Messages> }): LanguageMap\<T>

Créer une nouvelle table de langue contenant les messages fournis, fusionnés avec la définition actuelle. Le paramètre `additional` peut potentiellement remplacer des messages existants, créer de nouvelles langues ou même étendre la liste des messages (cas des messages spécifiques pour une extention, par exemple).

Expand All @@ -38,7 +38,7 @@ Indiquer si la table de langues contient la langue donnée. Cette méthode ne pe

Récupérer la liste des langues disponibles. Ce sont les langues pour lesquels la méthode `contains` renverrait vrai. Ce paramètre est en lecture seulement.

## messages(lang?: string): T | Partial<T>
## messages(lang?: string): T | Partial\<T>

Récupérer tous les messages pour un code de langue donné. Si la langue n'est pas disponible ou si le paramètre `lang` n'est pas donné, cela retournera les messages de la langue par défaut.

Expand All @@ -50,30 +50,34 @@ Récupérer tous les messages pour la langue par défaut. Ce paramètre est en l

Récupérer une chaine de caractère en JavaScript qui est une sérialisation de la table de caractère. Ce paramètre est en lecture seulement.

# Intl<T extends Messages>
# Intl\<T extends Messages>

Cette classe gère l'objet d'internationalisation. Elle est basée sur une table et des préférences de langues.

Le paramètre générique `T` représente le type de la langue par défaut.

## constructor(languages: LanguageMap<T>, preferences?: ReadonlyArray<string>, createGeneric: boolean = true)
## constructor(languages: LanguageMap\<T>, preferences?: ReadonlyArray\<string>, createGeneric: boolean = true)

Créer un objet d'internationalisation utilisant la table de langue donnée. Si le paramètre `preferences` est fourni, sa valeur sera utilisée pour l'ordre des préférences de langues de l'utilisateur. S'il est vrai, le paramètre `createGeneric` déclenche l'ajout automatique de code de langues plus génériques dans les préférences. Par exemple, si les préférences contiennent `no-NO-NY`, cela ajoutera automatiquement `no-NO` et `no` dans cet ordre après cette entrée. Ce paramètre peut être faux, par exemple dans le cas où l'on utilise les préférences linguistiques du navigateur, puisque l'utilisateur final peut déjà définir des préférences spécifiques et génériques.

Notez que les codes de langue sont formatés en minuscules et chiffres séparés par des soulignés. Cela signifie qu'au lieu de `no-NO-NY`, le code de langue réellement utilisé sera `no_no_ny`. Cela permet de normaliser l'écriture des codes de langue, en utilisant des caractères valides en tant que clés d'objet en TypeScript (évitant l'utilisation de guillemets).

## changePreferences(preferences: ReadonlyArray<string>, createGeneric: boolean = true): Intl<T>
## changePreferences(preferences: ReadonlyArray\<string>, createGeneric: boolean = true): Intl\<T>

Créer un nouvel objet d'internationalisation avec la même table de langues que celui-ci, mais de nouvelles préférences.

## t<K extends keyof T>(name: K, ...args: any[]): string
## preferences: ReadonlyArray\<string>

Les préférences réellement utilisées par l'objet. Seules les langues trouvées dans la table de langue sont conservées.

## t\<K extends keyof T>(name: K, ...args: any[]): string

Construire le message correspondant au nom donné avec les paramètres donnés dans la langue la plus appropriée. Cette méthode est en réalité surchargée afin que le type des paramètres soit controllé lors de la compilation par rapport aux paramètres attendus par le message.

## getMessage<K extends keyof T>(name: K): T[K]
## getMessage\<K extends keyof T>(name: K): T[K]

Récupérer le message correspondant au nom donné dans la langue la plus appropriée. Ce message n'est pas formaté et peut être soit une chaine de caractère, soit une fonction.

## languageMap: LanguageMap<T>
## languageMap: LanguageMap\<T>

Récupérer la table de langues utilisée. Ce paramètre est en lecture seulement.
5 changes: 5 additions & 0 deletions src/Intl.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ describe('Intl', () => {
)
})

it('must forget non existing language in preferences', () => {
const newLang = lang.changePreferences(['eo', 'dummy', 'fr'])
expect(newLang.preferences).to.have.ordered.members(['eo', 'fr'])
})

it('must be immutable', () => {
expect(lang.changePreferences(['anything'])).to.be.not.equal(lang)
})
Expand Down
9 changes: 5 additions & 4 deletions src/Intl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { LanguageMap } from './LanguageMap'
* Main class managing internationalization. Intl objects are immutable.
*/
export class Intl<T extends Messages> {
private readonly preferences: string[]
readonly preferences: ReadonlyArray<string>

/**
* Create a new Intl.
Expand All @@ -27,20 +27,21 @@ export class Intl<T extends Messages> {
preferences?: ReadonlyArray<string>,
createGeneric: boolean = true
) {
this.preferences = []
const _preferences: string[] = []
if (preferences) {
for (let preference of Intl.formatPreferences(
preferences,
createGeneric
)) {
if (
this.preferences.indexOf(preference) < 0 &&
_preferences.indexOf(preference) < 0 &&
this.languages.contains(preference)
) {
this.preferences.push(preference)
_preferences.push(preference)
}
}
}
this.preferences = _preferences
}

private static formatPreferences(
Expand Down

0 comments on commit 5d250f5

Please sign in to comment.