فهرست منبع

docs(vuepress): move 🇫🇷 doc in vuepress (#1412)

* doc(vuepress): move fr doc in vuepress

* move gitbook doc to vuepress

* fixup! move gitbook doc to vuepress
Antoine CARON 6 سال پیش
والد
کامیت
f64a89c514

+ 47 - 1
docs/.vuepress/config.js

@@ -29,6 +29,11 @@ module.exports = {
       lang: 'pt-BR',
       lang: 'pt-BR',
       title: 'Vuex',
       title: 'Vuex',
       description: 'Gerenciamento de Estado Centralizado para Vue.js'
       description: 'Gerenciamento de Estado Centralizado para Vue.js'
+    },
+    '/fr/': {
+        lang: 'fr-FR',
+        title: 'Vuex',
+        description: 'Gestion d\'état centralisé pour Vue.js'
     }
     }
   },
   },
   serviceWorker: true,
   serviceWorker: true,
@@ -280,7 +285,48 @@ module.exports = {
           '/ptbr/guide/testing',
           '/ptbr/guide/testing',
           '/ptbr/guide/hot-reload'
           '/ptbr/guide/hot-reload'
         ]
         ]
-      }
+      },
+      '/fr/': {
+          label: 'Français',
+          selectText: 'Langues',
+          editLinkText: 'Éditer la page sur GitHub',
+          nav: [
+              {
+                  text: 'Guide',
+                  link: '/guide/'
+              },
+              {
+                  text: 'API',
+                  link: '/api/'
+              },
+              {
+                  text: 'Notes de release',
+                  link: 'https://github.com/vuejs/vuex/releases'
+              }
+          ],
+          sidebar: [
+              '/fr/installation',
+              '/fr/',
+              '/fr/guide/',
+              {
+                  title: 'Concepts centraux',
+                  collapsable: false,
+                  children: [
+                      '/fr/guide/state',
+                      '/fr/guide/getters',
+                      '/fr/guide/mutations',
+                      '/fr/guide/actions',
+                      '/fr/guide/modules'
+                  ]
+              },
+              '/fr/guide/structure',
+              '/fr/guide/plugins',
+              '/fr/guide/strict',
+              '/fr/guide/forms',
+              '/fr/guide/testing',
+              '/fr/guide/hot-reload'
+          ]
+      },
     }
     }
   }
   }
 }
 }

+ 62 - 0
docs/fr/README.md

@@ -0,0 +1,62 @@
+# Vuex, qu'est-ce que c'est ?
+
+Vuex est un **_gestionnaire d'état (« state management pattern »)_ et une bibliothèque** pour des applications Vue.js. Il sert de zone de stockage de données centralisée pour tous les composants dans une application, avec des règles pour s'assurer que l'état ne puisse subir de mutations que d'une manière prévisible. Il s'intègre également avec [l'extension officielle](https://github.com/vuejs/vue-devtools) de Vue afin de fournir des fonctionnalités avancées comme de la visualisation d'état dans le temps et des exports et imports d’instantanés (« snapshot ») d'état.
+
+### Un « gestionnaire d'état », qu'est-ce que c'est ?
+
+Commençons par une simple application de comptage avec Vue :
+
+``` js
+new Vue({
+  // état
+  data () {
+    return {
+      count: 0
+    }
+  },
+  // vue
+  template: `
+    <div>{{ count }}</div>
+  `,
+  // actions
+  methods: {
+    increment () {
+      this.count++
+    }
+  }
+})
+```
+
+C'est une application autosuffisante avec les parties suivantes :
+
+- L'**état**, qui est la source de vérité qui pilote votre application,
+- La **vue**, qui est une réflexion déclarative de l'**état**,
+- Les **actions**, qui sont les façons possibles pour l'état de changer en réaction aux actions utilisateurs depuis la **vue**.
+
+Voici une représentation extrêmement simple du concept de « flux de donnée unidirectionnel » :
+
+<p style="text-align: center; margin: 2em">
+  <img style="width:100%;max-width:450px;" src="/flow.png">
+</p>
+
+Cependant, la simplicité s'évapore rapidement lorsque nous avons **de multiples composants qui partagent un même état global** :
+
+- Plusieurs vues peuvent dépendre de la même partie de l'état global.
+- Des actions dans différentes vues peuvent avoir besoin de muter la même partie de l'état global.
+
+Pour le premier problème, passer des props peut être fastidieux pour les composants profondément imbriqués, et ça ne fonctionne tout simplement pas pour les composants d'un même parent. Pour le deuxième problème, on se retrouve souvent à se rabattre sur des solutions telles qu'accéder aux références d'instance du parent/enfant direct ou essayer de muter et synchroniser de multiples copies de l'état via des évènements. Ces deux modèles sont fragiles et posent rapidement des problèmes de maintenabilité du code.
+
+Alors pourquoi ne pas extraire l'état global partagé des composants, et le gérer dans un singleton global ? De cette manière, notre arbre de composant devient une grosse « vue », et n'importe quel composant peut accéder à l'état global ou déclencher des actions, peu importe où il se trouve dans l'arbre !
+
+De plus, en définissant et en séparant les concepts impliqués dans la gestion de l'état global et en appliquant certaines règles, on donne aussi une structure et une maintenabilité à notre code.
+
+Voilà l'idée de base derrière Vuex, inspiré par [Flux](https://facebook.github.io/flux/docs/overview.html), [Redux](http://redux.js.org/) et [l'architecture Elm](https://guide.elm-lang.org/architecture/). À l'inverse des autres modèles, Vuex est aussi une bibliothèque d'implémentation conçue spécialement pour Vue.js afin de bénéficier de son système de réactivité granulaire pour des modifications efficaces.
+
+![vuex](/vuex.png)
+
+### Quand l'utiliser ?
+
+Bien que Vuex nous aide à gérer un état global partagé, il apporte aussi le cout de nouveaux concepts et _abstraction de code_ (« boilerplate »). C'est un compromis entre la productivité à court terme et à long terme.
+
+Si vous n'avez jamais créé une _application monopage_ à grande échelle et que vous sautez directement dans Vuex, cela peut paraitre verbeux et intimidant. C'est parfaitement normal ; si votre application est simple, vous vous en sortirez sans doute très bien sans Vuex. Un simple [canal d'évènement global](https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch) pourrait très bien vous suffire. Mais si vous devez créer une application monopage à moyenne ou grande échelle, il y a des chances que vous vous trouviez dans des situations qui vous feront vous interroger sur une meilleure gestion de l'état global, détaché de votre composant Vue, et Vuex sera naturellement la prochaine étape pour vous. Voici une bonne citation de Dan Abramov, l'auteur de Redux :
+> « Les librairies Flux, c'est comme les lunettes : vous saurez quand vous en aurez besoin. »

+ 251 - 0
docs/fr/api/README.md

@@ -0,0 +1,251 @@
+---
+sidebar: auto
+---
+
+# Documentation de l'API
+
+## Vuex.Store
+
+``` js
+import Vuex from 'vuex'
+
+const store = new Vuex.Store({ ...options })
+```
+
+## Options du constructeur de `Vuex.Store`
+
+### state
+
+  - type : `Object | Function`
+
+    L'objet d'état racine pour le store Vuex. [Plus de détails](../guide/state.md)
+
+    Si vous passez une fonction qui retourne un objet, l'objet retourné est utilisé en tant qu'état racine. Ceci est utile quand vous voulez réutiliser un objet d'état surtout dans un cas de réutilisation de module. [Plus de détails](../guide/modules.md#réutiliser-un-module)
+
+### mutations
+
+  - type : `{ [type: string]: Function }`
+
+    Enregistrer les mutations sur le store. La fonction gestionnaire reçoit toujours `state` comme premier argument (sera l'état local du module si défini dans un module), et reçoit le `payload` en second argument s'il y en a un.
+
+    [Plus de détails](../guide/mutations.md)
+
+### actions
+
+  - type : `{ [type: string]: Function }`
+
+    Enregistrer les actions sur le store. La fonction gestionnaire reçoit un objet `context` qui expose les propriétés suivantes :
+
+    ``` js
+    {
+      state,      // identique à `store.state`, ou à l'état local si dans des modules
+      rootState,  // identique à `store.state`, seulement dans des modules
+      commit,     // identique à `store.commit`
+      dispatch,   // identique à `store.dispatch`
+      getters,    // identique à `store.getters`, ou les accesseurs locaux dans les modules
+      rootGetters // identique à `store.getters`, seulement dans les modules
+    }
+    ```
+
+    [Plus de détails](../guide/actions.md)
+
+### getters
+
+  - type : `{ [key: string]: Function }`
+
+    Enregistrer les accesseurs sur le store. La fonction accesseur reçoit les arguments suivants :
+
+    ```
+    state,    // sera l'état local du module si défini dans un module.
+    getters   // identique à `store.getters`
+    ```
+
+    Arguments spécifiques quand défini dans un module
+
+    ```
+    state,       // sera l'état local du module si défini dans un module.
+    getters,     // module local getters of the current module
+    rootState,   // état global
+    rootGetters  // tous les accesseurs
+    ```
+
+    Les accesseurs enregistrés sont exposés sur `store.getters`.
+
+    [Plus de détails](../guide/getters.md)
+
+### modules
+
+  - type : `Object`
+
+    Un objet contenant des sous-modules qui seront regroupés dans le store, sous la forme suivante :
+
+    ``` js
+    {
+      key: {
+        state,
+        namespaced?,
+        mutations?,
+        actions?,
+        getters?,
+        modules?
+      },
+      ...
+    }
+    ```
+
+    Chaque module peut contenir `state` et `mutations`, tout comme les options racines. L'état d'un module sera attaché à l'état racine du store en utilisant la clé du module. Les mutations et accesseurs d'un module recevront seulement l'état local du module en premier argument au lieu de l'état racine, et le `context.state` des actions du module pointeront également vers l'état local.
+
+    [Plus de détails](../guide/modules.md)
+
+### plugins
+
+  - type : `Array<Function>`
+
+    Un tableau de fonctions plugins qui seront appliquées au store. Un plugin reçoit simplement le store comme seul argument et peut soit écouter les mutations (pour la persistance de données, les logs ou le débogage) ou propager des mutations (pour les données internes, c.-à-d. websockets ou observables).
+
+    [Plus de détails](../guide/plugins.md)
+
+### strict
+
+  - type : `Boolean`
+  - default: `false`
+
+    Force le store Vuex en mode strict. En mode strict, toute mutation de l'état en dehors des gestionnaires de mutation lancera une erreur.
+
+    [Plus de détails](../guide/strict.md)
+
+## Propriétés d'instance de `Vuex.Store`
+
+### state
+
+  - type : `Object`
+
+    L'état racine. Lecture seule.
+
+### getters
+
+  - type : `Object`
+
+    Expose les accesseurs enregistrés. Lecture seule.
+
+## Méthodes d'instance de `Vuex.Store`
+
+### commit
+
+-  `commit(type: string, payload?: any, options?: Object)`
+-  `commit(mutation: Object, options?: Object)`
+
+  Acter une mutation. `options` peut avoir `root: true` ce qui permet d'acter des mutations racines dans des [modules sous espace de nom](../guide/modules.md#namespacing). [Plus de détails](../guide/mutations.md)
+
+### dispatch
+
+-  `dispatch(type: string, payload?: any, options?: Object)`
+-  `dispatch(action: Object, options?: Object)`
+
+  Propager une action. Retourne la valeur renvoyée par le gestionnaire d'action déclenché, ou une Promesse si plusieurs gestionnaires ont été déclenchés. [Plus de détails](../guide/actions.md)
+
+### replaceState
+
+-  `replaceState(state: Object)`
+
+  Remplacer l'état racine du store. Utiliser seulement pour hydrater l'état ou dans le but de voyager dans le temps.
+
+### watch
+
+-  `watch(getter: Function, cb: Function, options?: Object)`
+
+  Observer de façon réactive la valeur de retour d'une fonction accesseur, et appeler la fonction de rappel lorsque la valeur change. L'accesseur reçoit l'état du store en premier argument, et les accesseurs en second argument. Accepte un objet optionnel d'options qui prend les mêmes options que la méthode `vm.$watch` de Vue.
+
+  Pour arrêter d'observer, appeler la fonction gestionnaire retournée.
+
+### subscribe
+
+-  `subscribe(handler: Function)`
+
+  S'abonner aux mutations du store. Le `handler` est appelé après chaque mutation et reçoit le descripteur de mutation et l'état post mutation comme arguments :
+
+  ``` js
+  store.subscribe((mutation, state) => {
+    console.log(mutation.type)
+    console.log(mutation.payload)
+  })
+  ```
+
+  Utilisé plus communément dans les plugins. [Plus de détails](../guide/plugins.md)
+
+### subscribeAction
+
+-  `subscribeAction(handler: Function)`
+
+  > Nouveau dans la 2.5.0+
+
+  S'abonner au actions du store. Le `handler` est appelé pour chaque action propagée et reçoit chaque description d'action et l'état du store courant en arguments :
+
+  ``` js
+  store.subscribeAction((action, state) => {
+    console.log(action.type)
+    console.log(action.payload)
+  })
+  ```
+
+  Souvent utiliser dans les plugins. [Pour plus de détails](../guide/plugins.md)
+
+### registerModule
+
+-  `registerModule(path: string | Array<string>, module: Module, options?: Object)`
+
+  Enregistrer un module dynamique. [Plus de détails](../guide/modules.md#enregistrement-dynamique-de-module)
+
+  `options` peut avoir `preserveState: true` qui lui permet de préserver l'état précédent. Utile pour du rendu côté serveur.
+
+### unregisterModule
+
+-  `unregisterModule(path: string | Array<string>)`
+
+  Supprimer un module dynamique. [Plus de détails](../guide/modules.md#enregistrement-dynamique-de-module)
+
+### hotUpdate
+
+-  `hotUpdate(newOptions: Object)`
+
+  Remplacement à la volée des nouvelles actions et mutations. [Plus de détails](../guide/hot-reload.md)
+
+## Fonctions utilitaires d'attachement au composant
+
+### mapState
+
+-  `mapState(namespace?: string, map: Array<string> | Object): Object`
+
+  Créer des propriétés calculées qui retournent le sous-arbre du store Vuex au composant. [Plus de détails](../guide/state.md#le-helper-mapstate)
+
+  Le premier argument peut être de façon optionnelle une chaine d'espace de nom. [Plus de détails](../guide/modules.md#Fonctions-utilitaires-liées-avec-espace-de-nom)
+
+### mapGetters
+
+-  `mapGetters(namespace?: string, map: Array<string> | Object): Object`
+
+  Créer des propriétés calculées qui retournent la valeur calculée d'un accesseur. [Plus de détails](../guide/getters.md#la-function-utilitaire-mapgetters)
+
+  Le premier argument peut être de façon optionnelle une chaine d'espace de nom. [Plus de détails](../guide/modules.md#Fonctions-utilitaires-liées-avec-espace-de-nom)
+
+### mapActions
+
+-  `mapActions(namespace?: string, map: Array<string> | Object): Object`
+
+  Créer des méthodes de composant qui propagent une action. [Plus de détails](../guide/actions.md#propager-des-actions-dans-les-composants)
+
+  Le premier argument peut être de façon optionnelle une chaine d'espace de nom. [Plus de détails](../guide/modules.md#Fonctions-utilitaires-liées-avec-espace-de-nom)
+
+### mapMutations
+
+-  `mapMutations(namespace?: string, map: Array<string> | Object): Object`
+
+  Créer des méthodes de composant qui actent une mutation. [Plus de détails](../guide/mutations.md#acter-des-mutations-dans-les-composants)
+
+  Le premier argument peut être de façon optionnelle une chaine d'espace de nom. [Plus de détails](../guide/modules.md#Fonctions-utilitaires-liées-avec-espace-de-nom)
+
+### createNamespacedHelpers
+
+-  `createNamespacedHelpers(namespace: string): Object`
+
+  Créer des fonctions utilitaires liées avec espace de nom. L'objet retourné contient `mapState`, `mapGetters`, `mapActions` et `mapMutations` qui sont liées à l'espace de nom fourni. [Plus de détails](../guide/modules.md#fonctions-utilitaires-liées-avec-espace-de-nom)

+ 44 - 0
docs/fr/guide/README.md

@@ -0,0 +1,44 @@
+# Pour commencer
+
+Au cœur de chaque application Vuex, il y a la **zone de stockage (« store »)**. Un « store » est tout simplement un conteneur avec l'**état (« state »)** de votre application. Il y a deux choses qui différencient un store Vuex d'un simple objet global :
+
+1. Les stores Vuex sont réactifs. Quand les composants Vue y récupèrent l'état, ils se mettront à jour de façon réactive et efficace si l'état du store a changé.
+
+2. Vous ne pouvez pas muter directement l'état du store. La seule façon de modifier l'état d'un store est d'**acter (« commit »)** explicitement des **mutations**. Cela assure que chaque état laisse un enregistrement traçable, et permet à des outils de nous aider à mieux appréhender nos applications.
+
+### Le store le plus simple
+
+> **NOTE:** Nous allons utiliser la syntaxe ES2015 dans les exemples de code pour le reste de la documentation. Si vous ne vous êtes pas encore penché dessus, [vous devriez](https://babeljs.io/docs/learn-es2015/) !
+
+Après [avoir installé](../installation.md) Vuex, nous allons créer un store. C'est assez simple ; définissez juste un objet d'état initial et quelques mutations :
+
+``` js
+// Assurez vous d'appeler `Vue.use(Vuex)` en premier lieu si vous utilisez un système de module
+
+const store = new Vuex.Store({
+  state: {
+    count: 0
+  },
+  mutations: {
+    increment (state) {
+      state.count++
+    }
+  }
+})
+```
+
+Maintenant, vous pouvez accéder à l'objet d'état avec `store.state`, et déclencher un changement d'état avec la méthode `store.commit` :
+
+``` js
+store.commit('increment')
+
+console.log(store.state.count) // -> 1
+```
+
+Encore une fois, la raison pour laquelle nous actons une mutation au lieu de modifier `store.state.count` directement, c'est parce que nous voulons le tracer explicitement. Cette simple convention rend votre intention plus explicite, ainsi vous pouvez raisonner plus facilement les changements d'état en lisant votre code. De plus, cela nous donne l'opportunité d'implémenter des outils qui peuvent enregistrer chaque mutation, prendre des instantanés de l'état, ou même procéder à de la visualisation d'état dans le temps.
+
+Utiliser l'état du store dans un composant implique simplement de retourner l'état dans une *propriété calculée*, car l'état du store est réactif. Déclencher des changements signifie simplement d'acter des mutations dans les méthodes du composant.
+
+Voici un exemple de l'[application de comptage Vuex la plus basique](https://jsfiddle.net/n9jmu5v7/1269/).
+
+Ensuite, nous allons examiner chaque concept de base plus en détails, et commençons avec l'[État](state.md).

+ 178 - 0
docs/fr/guide/actions.md

@@ -0,0 +1,178 @@
+# Actions
+
+Les actions sont similaires aux mutations, à la différence que :
+
+- Au lieu de modifier l'état, les actions actent des mutations.
+- Les actions peuvent contenir des opérations asynchrones.
+
+Enregistrons une simple action :
+
+``` js
+const store = new Vuex.Store({
+  state: {
+    count: 0
+  },
+  mutations: {
+    increment (state) {
+      state.count++
+    }
+  },
+  actions: {
+    increment (context) {
+      context.commit('increment')
+    }
+  }
+})
+```
+
+Les gestionnaires d'action reçoivent un objet contexte qui expose le même ensemble de méthodes et propriétés que l'instance du store, donc vous pouvez appeler `context.commit` pour acter une mutation, ou accéder à l'état et aux accesseurs via `context.state` et `context.getters`. Nous verrons pourquoi cet objet contexte n'est pas l'instance du store elle-même lorsque nous présenterons les [Modules](./modules.md) plus tard.
+
+En pratique, nous utilisons souvent la [déstructuration d'argument](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Op%C3%A9rateurs/Affecter_par_d%C3%A9composition) pour simplifier quelque peu le code (particulièrement si nous avons besoin d'appeler `commit` plusieurs fois) :
+
+``` js
+actions: {
+  increment ({ commit }) {
+    commit('increment')
+  }
+}
+```
+
+### Propager des actions
+
+Les actions sont déclenchées par la méthode `store.dispatch` :
+
+``` js
+store.dispatch('increment')
+```
+
+Cela peut sembler idiot au premier abord : si nous avons besoin d'incrémenter le compteur, pourquoi ne pas simplement appeler `store.commit('increment')` directement ? Vous rappelez-vous que **les mutations doivent être synchrones** ? Les actions ne suivent pas cette règle. Il est possible de procéder à des opérations **asynchrones** dans une action :
+
+``` js
+actions: {
+  incrementAsync ({ commit }) {
+    setTimeout(() => {
+      commit('increment')
+    }, 1000)
+  }
+}
+```
+
+Les actions prennent également en charge les paramètres additionnels (« payload ») et les objets pour propager :
+
+``` js
+// propager avec un paramètre additionnel
+store.dispatch('incrementAsync', {
+  amount: 10
+})
+
+// propager avec un objet
+store.dispatch({
+  type: 'incrementAsync',
+  amount: 10
+})
+```
+
+Un exemple concret d'application serait une action pour vider un panier d'achats, ce qui implique **d'appeler une API asynchrone** et d'**acter de multiples mutations** :
+
+``` js
+actions: {
+  checkout ({ commit, state }, products) {
+    // sauvegarder les articles actuellement dans le panier
+    const savedCartItems = [...state.cart.added]
+    // envoyer la requête de checkout,
+    // et vider le panier
+    commit(types.CHECKOUT_REQUEST)
+    // l'API de la boutique en ligne prend une fonction de rappel en cas de succès et une autre en cas d'échec
+    shop.buyProducts(
+      products,
+      // gérer le succès
+      () => commit(types.CHECKOUT_SUCCESS),
+      // gérer l'échec
+      () => commit(types.CHECKOUT_FAILURE, savedCartItems)
+    )
+  }
+}
+```
+
+Notez que nous procédons à un flux d'opérations asynchrones, et enregistrons les effets de bord (mutation de l'état) de l'action en les actant.
+
+### Propager des actions dans les composants
+
+Vous pouvez propager des actions dans les composants avec `this.$store.dispatch('xxx')`, ou en utilisant la fonction utilitaire `mapActions` qui attache les méthodes du composant aux appels de `store.dispatch` (nécessite l'injection de `store` à la racine) :
+
+``` js
+import { mapActions } from 'vuex'
+
+export default {
+  // ...
+  methods: {
+    ...mapActions([
+      'increment' // attacher `this.increment()` à `this.$store.dispatch('increment')`
+
+      // `mapActions` supporte également les paramètres additionnels :
+      'incrementBy' // attacher `this.incrementBy(amount)` à `this.$store.dispatch('incrementBy', amount)`
+    ]),
+    ...mapActions({
+      add: 'increment' // attacher `this.add()` à `this.$store.dispatch('increment')`
+    })
+  }
+}
+```
+
+### Composer les actions
+
+Les actions sont souvent asynchrones, donc comment savoir lorsqu'une action est terminée ? Et plus important, comment composer plusieurs actions ensemble pour manipuler des flux asynchrones plus complexes ?
+
+La première chose à savoir est que `store.dispatch` peut gérer la Promesse (« Promise ») retournée par le gestionnaire d'action déclenché et par conséquent vous pouvez également retourner une Promesse :
+
+``` js
+actions: {
+  actionA ({ commit }) {
+    return new Promise((resolve, reject) => {
+      setTimeout(() => {
+        commit('someMutation')
+        resolve()
+      }, 1000)
+    })
+  }
+}
+```
+
+Maintenant vous pouvez faire :
+
+``` js
+store.dispatch('actionA').then(() => {
+  // ...
+})
+```
+
+Et également dans une autre action :
+
+``` js
+actions: {
+  // ...
+  actionB ({ dispatch, commit }) {
+    return dispatch('actionA').then(() => {
+      commit('someOtherMutation')
+    })
+  }
+}
+```
+
+Pour finir, si nous utilisons [`async` / `await`](https://tc39.github.io/ecmascript-asyncawait/), nous pouvons composer nos actions ainsi :
+
+``` js
+// sachant que `getData()` et `getOtherData()` retournent des Promesses.
+
+actions: {
+  async actionA ({ commit }) {
+    commit('gotData', await getData())
+  },
+  async actionB ({ dispatch, commit }) {
+    await dispatch('actionA') // attendre que `actionA` soit finie
+    commit('gotOtherData', await getOtherData())
+  }
+}
+```
+
+> Il est possible pour un `store.dispatch` de déclencher plusieurs gestionnaires d'action dans différents modules. Dans ce genre de cas, la valeur retournée sera une Promesse qui se résout quand tous les gestionnaires déclenchés ont été résolus.

+ 60 - 0
docs/fr/guide/forms.md

@@ -0,0 +1,60 @@
+# Gestion des formulaires
+
+Lorsque l'on utilise Vuex en mode strict, il peut être compliqué d'utiliser `v-model` sur une partie de l'état qui appartient à Vuex :
+
+``` html
+<input v-model="obj.message">
+```
+
+Supposons que `obj` est une propriété calculée qui retourne un objet depuis le store, le `v-model` tentera de muter directement `obj.message` lorsque l'utilisateur saisit du texte dans le champ. En mode strict, cela produira une erreur car la mutation n'est pas effectuée dans un gestionnaire de mutation Vuex explicite.
+
+La « méthode Vuex » pour gérer ça est de lier la valeur de l'`input` et d'appeler une action sur l'évènement `input` ou `change` :
+
+``` html
+<input :value="message" @input="updateMessage">
+```
+``` js
+// ...
+computed: {
+  ...mapState({
+    message: state => state.obj.message
+  })
+},
+methods: {
+  updateMessage (e) {
+    this.$store.commit('updateMessage', e.target.value)
+  }
+}
+```
+
+Et voici le gestionnaire de mutation :
+
+``` js
+// ...
+mutations: {
+  updateMessage (state, message) {
+    state.obj.message = message
+  }
+}
+```
+
+### Propriété calculée bidirectionnelle
+
+Admettons tout de même que l'exemple ci-dessus est plus verbeux que le `v-model` couplé à l'état local (tout en perdant quelques fonctionnalités pratiques de `v-model` au passage). Une approche alternative consiste à utiliser une propriété calculée bidirectionnelle avec un mutateur :
+
+``` html
+<input v-model="message">
+```
+``` js
+// ...
+computed: {
+  message: {
+    get () {
+      return this.$store.state.obj.message
+    },
+    set (value) {
+      this.$store.commit('updateMessage', value)
+    }
+  }
+}
+```

+ 116 - 0
docs/fr/guide/getters.md

@@ -0,0 +1,116 @@
+# Accesseurs
+
+Parfois nous avons besoin de calculer des valeurs basées sur l'état du store, par exemple pour filtrer une liste d'éléments et les compter :
+
+``` js
+computed: {
+  doneTodosCount () {
+    return this.$store.state.todos.filter(todo => todo.done).length
+  }
+}
+```
+
+Si plus d'un composant a besoin d'utiliser cela, il nous faut ou bien dupliquer cette fonction, ou bien l'extraire dans une fonction utilitaire séparée et l'importer aux endroits nécessaires. Les deux idées sont loin d'être idéales.
+
+Vuex nous permet de définir des accesseurs (« getters ») dans le store. Voyez-les comme les propriétés calculées des stores. Comme pour les propriétés calculées, le résultat de l'accesseur est mis en cache en se basant sur ses dépendances et il ne sera réévalué que lorsque l'une de ses dépendances aura changée.
+
+Les accesseurs prennent l'état en premier argument :
+
+``` js
+const store = new Vuex.Store({
+  state: {
+    todos: [
+      { id: 1, text: '...', done: true },
+      { id: 2, text: '...', done: false }
+    ]
+  },
+  getters: {
+    doneTodos: state => {
+      return state.todos.filter(todo => todo.done)
+    }
+  }
+})
+```
+
+### Accès par propriété
+
+Les accesseurs seront exposés sur l'objet `store.getters` et vous accèderez aux valeurs comme des propriétés :
+
+``` js
+store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
+```
+
+Les accesseurs recevront également les autres accesseurs en second argument :
+
+``` js
+getters: {
+  // ...
+  doneTodosCount: (state, getters) => {
+    return getters.doneTodos.length
+  }
+}
+```
+
+``` js
+store.getters.doneTodosCount // -> 1
+```
+
+Nous pouvons maintenant facilement les utiliser dans n'importe quel composant :
+
+``` js
+computed: {
+  doneTodosCount () {
+    return this.$store.getters.doneTodosCount
+  }
+}
+```
+
+Notez que les accesseurs accédés par propriétés sont mis en cache par le système de réactivité de Vue.
+
+### Accès par méthode
+
+Vous pouvez aussi passer des arguments aux accesseurs en retournant une fonction. Cela est particulièrement utile quand vous souhaitez interroger un tableau dans le store :
+
+```js
+getters: {
+  // ...
+  getTodoById: (state) => (id) => {
+    return state.todos.find(todo => todo.id === id)
+  }
+}
+```
+
+``` js
+store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
+```
+
+Notez que les accesseur accédés par méthodes vont être exécuté chaque fois qu'il seront appelés. Le résultat ne sera donc pas mis en cache.
+
+### La fonction utilitaire `mapGetters`
+
+La fonction utilitaire `mapGetters` attache simplement vos accesseurs du store aux propriétés calculées locales :
+
+``` js
+import { mapGetters } from 'vuex'
+
+export default {
+  // ...
+  computed: {
+    // rajouter les accesseurs dans `computed` avec l'opérateur de décomposition
+    ...mapGetters([
+      'doneTodosCount',
+      'anotherGetter',
+      // ...
+    ])
+  }
+}
+```
+
+Si vous voulez attacher un accesseur avec un nom différent, utilisez un objet :
+
+``` js
+...mapGetters({
+  // attacher `this.doneCount` à `this.$store.getters.doneTodosCount`
+  doneCount: 'doneTodosCount'
+})
+```

+ 44 - 0
docs/fr/guide/hot-reload.md

@@ -0,0 +1,44 @@
+# Rechargement à chaud
+
+Vuex prend en charge le rechargement à chaud des mutations, modules, actions et accesseurs durant le développement, en utilisant l'[API du module de remplacement à chaud](https://webpack.js.org/guides/hot-module-replacement/) de webpack. Vous pouvez également utiliser Browserify avec le plugin [browserify-hmr](https://github.com/AgentME/browserify-hmr/).
+
+Pour les mutations et les modules, vous aurez besoin d'utiliser la méthode d'API `store.hotUpdate()` :
+
+``` js
+// store.js
+import Vue from 'vue'
+import Vuex from 'vuex'
+import mutations from './mutations'
+import moduleA from './modules/a'
+
+Vue.use(Vuex)
+
+const state = { ... }
+
+const store = new Vuex.Store({
+  state,
+  mutations,
+  modules: {
+    a: moduleA
+  }
+})
+
+if (module.hot) {
+  // accepter les actions et mutations en tant que module à chaud
+  module.hot.accept(['./mutations', './modules/a'], () => {
+    // requiert les modules à jour
+    // ajout de `.default` ici pour les sorties des modules babel 6
+    const newMutations = require('./mutations').default
+    const newModuleA = require('./modules/a').default
+    // remplacer les nouvelles actions et mutations
+    store.hotUpdate({
+      mutations: newMutations,
+      modules: {
+        a: newModuleA
+      }
+    })
+  })
+}
+```
+
+Jetez un œil à [l'exemple counter-hot](https://github.com/vuejs/vuex/tree/dev/examples/counter-hot) pour jouer avec du rechargement à chaud.

+ 319 - 0
docs/fr/guide/modules.md

@@ -0,0 +1,319 @@
+# Modules
+
+Du fait de l'utilisation d'un arbre d'état unique, tout l'état de notre application est contenu dans un seul et même gros objet. Cependant, au fur et à mesure que notre application grandit, le store peut devenir très engorgé.
+
+Pour y remédier, Vuex nous permet de diviser notre store en **modules**. Chaque module peut contenir ses propres états, mutations, actions, accesseurs. Il peut même contenir ses propres modules internes.
+
+``` js
+const moduleA = {
+  state: { ... },
+  mutations: { ... },
+  actions: { ... },
+  getters: { ... }
+}
+
+const moduleB = {
+  state: { ... },
+  mutations: { ... },
+  actions: { ... }
+}
+
+const store = new Vuex.Store({
+  modules: {
+    a: moduleA,
+    b: moduleB
+  }
+})
+
+store.state.a // -> l'état du `moduleA`
+store.state.b // -> l'état du `moduleB`
+```
+
+### État local d'un module
+
+Dans les mutations et accesseurs d'un module, le premier argument reçu sera **l'état local du module**.
+
+``` js
+const moduleA = {
+  state: { count: 0 },
+  mutations: {
+    increment (state) {
+      // `state` est l'état du module local
+      state.count++
+    }
+  },
+
+  getters: {
+    doubleCount (state) {
+      return state.count * 2
+    }
+  }
+}
+```
+
+De façon similaire, dans les actions du module, `context.state` exposera l'état local, et l'état racine sera disponible avec `context.rootState` :
+
+``` js
+const moduleA = {
+  // ...
+  actions: {
+    incrementIfOddOnRootSum ({ state, commit, rootState }) {
+      if ((state.count + rootState.count) % 2 === 1) {
+        commit('increment')
+      }
+    }
+  }
+}
+```
+
+Également, dans les accesseurs du module, l'état racine sera exposé en troisième argument :
+
+``` js
+const moduleA = {
+  // ...
+  getters: {
+    sumWithRootCount (state, getters, rootState) {
+      return state.count + rootState.count
+    }
+  }
+}
+```
+
+### Espace de nom
+
+Par défaut, les actions, mutations et accesseurs à l'intérieur d'un module sont toujours enregistrés sous l'**espace de nom global**. Cela permet à de multiples modules d'être réactifs au même type de mutation et d'action.
+
+Si vous souhaitez que votre module soit autosuffisant et réutilisable, vous pouvez le ranger sous un espace de nom avec `namespaced: true`. Quand le module est enregistré, tous ses accesseurs, actions et mutations seront automatiquement basés sur l'espace de nom du module dans lesquels ils sont rangés. Par exemple :
+
+```js
+const store = new Vuex.Store({
+  modules: {
+    account: {
+      namespaced: true,
+
+      // propriétés du module
+      state: { ... }, // l'état du module est déjà imbriqué et n'est pas affecté par l'option `namespace`
+      getters: {
+        isAdmin () { ... } // -> getters['account/isAdmin']
+      },
+      actions: {
+        login () { ... } // -> dispatch('account/login')
+      },
+      mutations: {
+        login () { ... } // -> commit('account/login')
+      },
+
+      // modules imbriqués
+      modules: {
+        // hérite de l'espace de nom du module parent
+        myPage: {
+          state: { ... },
+          getters: {
+            profile () { ... } // -> getters['account/profile']
+          }
+        },
+
+        // utilise un espace de nom imbriqué
+        posts: {
+          namespaced: true,
+
+          state: { ... },
+          getters: {
+            popular () { ... } // -> getters['account/posts/popular']
+          }
+        }
+      }
+    }
+  }
+})
+```
+
+Les accesseurs et actions sous espace de nom reçoivent des `getters`, `dispatch` et `commit` localisés. En d'autres termes, vous pouvez utiliser les paramètres de module sans écrire de préfixe dans ce même module. Permuter entre un espace de nom ou non n'affecte pas le code à l'intérieur du module.
+
+#### Accéder aux propriétés globales dans les modules à espace de nom
+
+Si vous voulez utiliser des états et accesseurs globaux, `rootState` et `rootGetters` sont passés en 3ᵉ et 4ᵉ arguments des fonctions d'accès et sont également exposés en tant que propriété de l'objet `context` passé aux fonctions d'action.
+
+Pour propager les actions ou les mutations actées dans l'espace de nom global, passez `{ root: true }` en 3ᵉ argument à `dispatch` et `commit`.
+
+``` js
+modules: {
+  foo: {
+    namespaced: true,
+
+    getters: {
+      // Les `getters` sont localisés dans le module des accesseurs
+      // vous pouvez utiliser `rootGetters` via le 4ᵉ argument des accesseurs
+      someGetter (state, getters, rootState, rootGetters) {
+        getters.someOtherGetter // -> 'foo/someOtherGetter'
+        rootGetters.someOtherGetter // -> 'someOtherGetter'
+      },
+      someOtherGetter: state => { ... }
+    },
+
+    actions: {
+      // les actions et mutations sont aussi localisées pour ce module
+      // elles vont accepter une option `root` pour la racine des actions et mutations.
+      someAction ({ dispatch, commit, getters, rootGetters }) {
+        getters.someGetter // -> 'foo/someGetter'
+        rootGetters.someGetter // -> 'someGetter'
+
+        dispatch('someOtherAction') // -> 'foo/someOtherAction'
+        dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'
+
+        commit('someMutation') // -> 'foo/someMutation'
+        commit('someMutation', null, { root: true }) // -> 'someMutation'
+      },
+      someOtherAction (ctx, payload) { ... }
+    }
+  }
+}
+```
+
+#### Enregistrer des actions globales dans des modules avec espace de nom
+
+Si vous voulez enregistrer des actions globales dans des modules avec espace de nom, vous pouvez les marquer avec `root: true` et placer la définition de l'action dans une fonction `handler`. Par exemple :
+
+``` js
+{
+  actions: {
+    someOtherAction ({dispatch}) {
+      dispatch('someAction')
+    }
+  },
+  modules: {
+    foo: {
+      namespaced: true,
+       actions: {
+        someAction: {
+          root: true,
+          handler (namespacedContext, payload) { ... } // -> 'someAction'
+        }
+      }
+    }
+  }
+}
+```
+
+#### Fonctions utilitaires liées avec espace de nom
+
+Quand nous lions un module sous espace de nom à un composant avec les fonctions utilitaires `mapState`, `mapGetters`, `mapActions` and `mapMutations`, cela peut être légèrement verbeux :
+
+``` js
+computed: {
+  ...mapState({
+    a: state => state.some.nested.module.a,
+    b: state => state.some.nested.module.b
+  })
+},
+methods: {
+  ...mapActions([
+    'some/nested/module/foo', // -> this['some/nested/module/foo']()
+    'some/nested/module/bar' // -> this['some/nested/module/bar']()
+  ])
+}
+```
+
+Dans ces cas-là, vous pouvez passer une chaine de caractère représentant le nom d'espace en tant que premier argument aux fonctions utilitaires ainsi toutes les liaisons seront faites en utilisant le module comme contexte. Cela peut être simplifié comme ci-dessous :
+
+``` js
+computed: {
+  ...mapState('some/nested/module', {
+    a: state => state.a,
+    b: state => state.b
+  })
+},
+methods: {
+  ...mapActions('some/nested/module', [
+    'foo', // -> this.foo()
+    'bar' // -> this.bar()
+  ])
+}
+```
+
+De plus, vous pouvez créer des fonctions utilitaires liées avec espace de nom en utilisant `createNamespacedHelpers`. Cela retourne un objet qui a les nouvelles fonctions utilitaires rattachées à la valeur d'espace de nom fournie :
+
+``` js
+import { createNamespacedHelpers } from 'vuex'
+
+const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')
+
+export default {
+  computed: {
+    // vérifie dans `some/nested/module`
+    ...mapState({
+      a: state => state.a,
+      b: state => state.b
+    })
+  },
+  methods: {
+    // vérifie dans `some/nested/module`
+    ...mapActions([
+      'foo',
+      'bar'
+    ])
+  }
+}
+```
+
+#### Limitations pour les plugins des développeurs
+
+Vous devez faire attention au nom d'espace imprévisible pour vos modules quand vous créez un [plugin](./plugins.md) qui fournit les modules et laisser les utilisateurs les ajouter au store de Vuex. Vos modules seront également sous espace de nom si l'utilisateur du plugin l'ajoute sous un module sous espace de nom. Pour vous adapter à la situation, vous devez recevoir la valeur de l'espace de nom via vos options de plugin :
+
+```js
+// passer la valeur d'espace de nom via une option du plugin
+// et retourner une fonction de plugin Vuex
+export function createPlugin (options = {}) {
+  return function (store) {
+    // ajouter l'espace de nom aux types de module
+    const namespace = options.namespace || ''
+    store.dispatch(namespace + 'pluginAction')
+ }
+}
+```
+
+### Enregistrement dynamique de module
+
+Vous pouvez enregistrer un module **après** que le store ait été créé avec la méthode `store.registerModule` :
+
+``` js
+// enregistrer un module `myModule`
+store.registerModule('myModule', {
+  // ...
+})
+
+// enregistrer un module imbriqué `nested/myModule`
+store.registerModule(['nested', 'myModule'], {
+  // ...
+})
+```
+
+L'état des modules est disponible dans `store.state.myModule` et `store.state.nested.myModule`.
+
+L'enregistrement dynamique de module permet aux autres plugins Vue de bénéficier de la gestion de l'état de Vuex en attachant un module au store de l'application. Par exemple, la bibliothèque [`vuex-router-sync`](https://github.com/vuejs/vuex-router-sync) intègre vue-router avec vuex en gérant l'état de la route d'application dans un module enregistré dynamiquement.
+
+Vous pouvez aussi supprimer un module enregistré dynamiquement avec `store.unregisterModule(moduleName)`. Notez que vous ne pouvez pas supprimer des modules statiques (déclarés à la création du store) avec cette méthode.
+
+Il est possible que vous souhaitiez préserver un état précédent quand vous abonnez un nouveau module. Par exemple préserver l'état depuis l'application rendue côté serveur. Vous pouvez réaliser ceci avec l'option `preserveState` : `store.registerModule('a', module, { preserveState: true })`.
+
+### Réutiliser un module
+
+Parfois nous devrons créer de multiples instances d'un module pour, par exemple :
+
+- créer plusieurs stores qui utilisent le même module (par ex. pour [éviter les singletons d'état avec du SSR](https://ssr.vuejs.org/fr/structure.html#avoid-stateful-singletons) quand l'option `runInNewContext` est à `false` ou `'once'`) ou
+- enregistrer le même module plusieurs fois dans le même store.
+
+Si nous utilisons un objet pour déclarer l'état du module, alors cet objet d'état sera partagé par référence et causera de contamination inter store/module quand il sera muté.
+
+C'est exactement le même problème qu'avec `data` dans un composant Vue. Ainsi la solution est là même, utiliser une fonction pour déclarer notre état de module (supporté par la 2.3.0+) :
+
+``` js
+const MyReusableModule = {
+  state () {
+    return {
+      foo: 'bar'
+    }
+  },
+  // mutations, actions, accesseurs...
+}
+```

+ 172 - 0
docs/fr/guide/mutations.md

@@ -0,0 +1,172 @@
+# Mutations
+
+La seule façon de vraiment modifier l'état dans un store Vuex est d'acter une mutation. Les mutations Vuex sont très similaires aux évènements : chaque mutation a un **type** sous forme de chaine de caractères et un **gestionnaire**. La fonction de gestion est en charge de procéder aux véritables modifications de l'état, et elle reçoit l'état en premier argument :
+
+``` js
+const store = new Vuex.Store({
+  state: {
+    count: 1
+  },
+  mutations: {
+    increment (state) {
+      // muter l'état
+      state.count++
+    }
+  }
+})
+```
+
+Vous ne pouvez pas appeler directement un gestionnaire de mutation. Le parti-pris ici est proche de l'abonnement à un évènement : « Lorsqu'une mutation du type `increment` est déclenchée, appelle ce gestionnaire. » Pour invoquer un gestionnaire de mutation, il faut appeler `store.commit` avec son type :
+
+``` js
+store.commit('increment')
+```
+
+### Acter avec un argument additionnel
+
+Vous pouvez donner un argument additionnel (« payload ») à la fonction `store.commit` lors de la mutation :
+
+``` js
+// ...
+mutations: {
+  increment (state, n) {
+    state.count += n
+  }
+}
+```
+``` js
+store.commit('increment', 10)
+```
+
+Dans la plupart des cas, l'argument additionnel devrait être un objet, ainsi il peut contenir plusieurs champs, et les mutations enregistrées seront également plus descriptives :
+
+``` js
+// ...
+mutations: {
+  increment (state, payload) {
+    state.count += payload.amount
+  }
+}
+```
+
+``` js
+store.commit('increment', {
+  amount: 10
+})
+```
+
+### Acter avec un objet
+
+Une méthode alternative pour acter une mutation est d'utiliser directement un objet qui a une propriété `type` :
+
+``` js
+store.commit({
+  type: 'increment',
+  amount: 10
+})
+```
+
+Lors de l'utilisation d'un objet pour acter, c'est l'objet lui-même qui ferra office d'argument pour aux gestionnaires de mutation, le gestionnaire reste donc inchangé :
+
+``` js
+mutations: {
+  increment (state, payload) {
+    state.count += payload.amount
+  }
+}
+```
+
+### Les mutations suivent les règles de réactivité de Vue
+
+Puisqu'un état de store de Vuex est rendu réactif par Vue, lorsque nous mutons l'état, les composants Vue observant cet état seront automatiquement mis à jour. Cela signifie également que les mutations Vuex sont sujettes aux mêmes limitations qu'avec l'utilisation de Vue seul :
+
+1. Initialisez de préférence le store initial de votre état avec tous les champs désirés auparavant.
+
+2. Lorsque vous ajoutez de nouvelles propriétés à un objet, vous devriez soit :
+
+  - Utiliser `Vue.set(obj, 'newProp', 123)`, ou
+
+  - Remplacer cet objet par un nouvel objet. Par exemple, en utilisant [opérateur de décomposition](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Op%C3%A9rateurs/Op%C3%A9rateur_de_d%C3%A9composition) (stage-2), il est possible d'écrire :
+
+    ``` js
+    state.obj = { ...state.obj, newProp: 123 }
+    ```
+
+### Utilisation de constante pour les types de mutation
+
+C'est une façon de faire régulière que d'utiliser des constantes pour les types de mutations dans diverses implémentations de Flux. Cela permet au code de bénéficier d'outils comme les linters (des outils d'aide à l'analyse syntaxique), et écrire toutes ces constantes dans un seul fichier permet à vos collaborateurs d'avoir un aperçu de quelles mutations sont possibles dans toute l'application :
+
+``` js
+// mutation-types.js
+export const SOME_MUTATION = 'SOME_MUTATION'
+```
+
+``` js
+// store.js
+import Vuex from 'vuex'
+import { SOME_MUTATION } from './mutation-types'
+
+const store = new Vuex.Store({
+  state: { ... },
+  mutations: {
+    // nous pouvons utiliser la fonctionnalité de nom de propriété calculée
+    // pour utiliser une constante en tant que nom de fonction
+    [SOME_MUTATION] (state) {
+      // muter l'état
+    }
+  }
+})
+```
+
+Utiliser les constantes ou non relève de la préférence personnelle. Cela peut être bénéfique sur un gros projet avec beaucoup de développeurs, mais c'est totalement optionnel si vous n'aimez pas cette pratique.
+
+### Les mutations doivent être synchrones
+
+Une règle importante à retenir est que **les fonctions de gestion des mutations doivent être synchrones**. Pourquoi ? Considérons l'exemple suivant :
+
+``` js
+mutations: {
+  someMutation (state) {
+    api.callAsyncMethod(() => {
+      state.count++
+    })
+  }
+}
+```
+
+Maintenant imaginons que nous déboguons l'application et que nous regardons dans les logs de mutation des outils de développement (« devtools »). Pour chaque mutation enregistrée, le devtool aura besoin de capturer un instantané de l'état « avant » et un instantané « après ». Cependant, la fonction de rappel asynchrone de l'exemple ci-dessus rend l'opération impossible : la fonction de rappel n'est pas encore appelée lorsque la mutation est actée, et il n'y a aucun moyen pour le devtool de savoir quand la fonction de rappel sera véritablement appelée. Toute mutation d'état effectuée dans la fonction de rappel est essentiellement intraçable !
+
+### Acter des mutations dans les composants
+
+Vous pouvez acter des mutations dans les composants avec `this.$store.commit('xxx')`, ou en utilisant la fonction utilitaire `mapMutations` qui attache les méthodes du composant aux appels de `store.commit` (nécessite l'injection de `store` à la racine) :
+
+``` js
+import { mapMutations } from 'vuex'
+
+export default {
+  // ...
+  methods: {
+    ...mapMutations([
+      'increment' // attacher `this.increment()` à `this.$store.commit('increment')`
+
+      // `mapMutations` supporte également les paramètres additionnels :
+      'incrementBy' // attacher `this.incrementBy(amount)` à `this.$store.commit('incrementBy', amount)`
+    ]),
+    ...mapMutations({
+      add: 'increment' // attacher `this.add()` à `this.$store.commit('increment')`
+    })
+  }
+}
+```
+
+### En avant vers les actions
+
+L'asynchronisme combiné à la mutation de l'état peut rendre votre programme très difficile à comprendre. Par exemple, lorsque vous appelez deux méthodes avec toutes les deux des fonctions de rappel asynchrones qui changent l'état, comment savez-vous quelle fonction de rappel est appelée en première ? C'est exactement la raison pour laquelle nous voulons séparer les deux concepts. Avec Vuex, **les mutations sont des transactions synchrones** :
+
+``` js
+store.commit('increment')
+// n'importe quel changement d'état de « increment » par mutation
+// devrait être faite de manière synchrone.
+```
+
+Pour gérer les opérations asynchrones, tournons-nous vers les [Actions](actions.md).

+ 126 - 0
docs/fr/guide/plugins.md

@@ -0,0 +1,126 @@
+# Plugins
+
+Les stores Vuex prennent une option `plugins` qui expose des hooks pour chaque mutation. Un plugin Vuex est simplement une fonction qui reçoit un store comme unique argument :
+
+``` js
+const myPlugin = store => {
+  // appelé quand le store est initialisé
+  store.subscribe((mutation, state) => {
+    // appelé après chaque mutation.
+    // Les mutations arrivent au format `{ type, payload }`.
+  })
+}
+```
+
+Et peut être utilisé ainsi :
+
+``` js
+const store = new Vuex.Store({
+  // ...
+  plugins: [myPlugin]
+})
+```
+
+### Acter des mutations dans des plugins
+
+Les plugins ne sont pas autorisés à muter directement l'état. Tout comme vos composants, ils peuvent simplement déclencher des changements en actant des mutations.
+
+En actant des mutations, un plugin peut être utilisé pour synchroniser la source de données avec le store. Par exemple, pour synchroniser la source de données d'une websocket vers le store (c'est juste un exemple artificiel, en réalité la fonction `createPlugin` peut prendre des options additionnelles pour des tâches plus complexes) :
+
+``` js
+export default function createWebSocketPlugin (socket) {
+  return store => {
+    socket.on('data', data => {
+      store.commit('receiveData', data)
+    })
+    store.subscribe(mutation => {
+      if (mutation.type === 'UPDATE_DATA') {
+        socket.emit('update', mutation.payload)
+      }
+    })
+  }
+}
+```
+
+``` js
+const plugin = createWebSocketPlugin(socket)
+
+const store = new Vuex.Store({
+  state,
+  mutations,
+  plugins: [plugin]
+})
+```
+
+### Prendre des instantanés de l'état
+
+Parfois un plugin peut vouloir recevoir des « instantanés » de l'état, et également comparer l'état post mutation avec l'état prémutation. Pour faire ceci, vous aurez besoin d'effectuer une copie complète de l'état :
+
+``` js
+const myPluginWithSnapshot = store => {
+  let prevState = _.cloneDeep(store.state)
+  store.subscribe((mutation, state) => {
+    let nextState = _.cloneDeep(state)
+
+    // comparer `prevState` et `nextState`...
+
+    // sauver l'état pour la prochaine mutation
+    prevState = nextState
+  })
+}
+```
+
+**Les plugins qui peuvent prendre des instantanés ne devraient être utilisés que pendant le développement.** Lorsqu'on utilise webpack ou Browserify, on peut laisser nos outils de développement (« devtools ») s'occuper de ça pour nous :
+
+``` js
+const store = new Vuex.Store({
+  // ...
+  plugins: process.env.NODE_ENV !== 'production'
+    ? [myPluginWithSnapshot]
+    : []
+})
+```
+
+Le plugin sera utilisé par défaut. Pour la production, vous aurez besoin de [DefinePlugin](https://webpack.js.org/plugins/define-plugin/) pour webpack ou de [envify](https://github.com/hughsk/envify) pour Browserify pour convertir la valeur de `process.env.NODE_ENV !== 'production'` à `false` pour le build final.
+
+### Plugin de logs intégré
+
+> Si vous utilisez [vue-devtools](https://github.com/vuejs/vue-devtools) vous n'avez probablement pas besoin de ça.
+
+Vuex fournit un plugin de logs à des fins de débogage :
+
+``` js
+import createLogger from 'vuex/dist/logger'
+
+const store = new Vuex.Store({
+  plugins: [createLogger()]
+})
+```
+
+La fonction `createLogger` prend quelques options :
+
+``` js
+const logger = createLogger({
+  collapsed: false, // auto-expand logged mutations
+  filter (mutation, stateBefore, stateAfter) {
+    // retourne `true` si une mutation devrait être logguée
+    // `mutation` est un `{ type, payload }`
+    return mutation.type !== "aBlacklistedMutation"
+  },
+  transformer (state) {
+    // transforme l'état avant de le logguer.
+    // retourne par exemple seulement un sous-arbre spécifique
+    return state.subTree
+  },
+  mutationTransformer (mutation) {
+    // les mutations sont logguées au format `{ type, payload }`
+    // nous pouvons les formater comme nous le souhaitons.
+    return mutation.type
+  },
+  logger: console, // implementation de l'API `console`, par défaut `console`
+})
+```
+
+Le fichier de logs peut aussi être inclus directement via une balise `script`, et exposera la fonction `createVuexLogger` globalement.
+
+Notez que le plugin de logs peut prendre des instantanés de l'état, ne l'utilisez donc que durant le développement.

+ 109 - 0
docs/fr/guide/state.md

@@ -0,0 +1,109 @@
+# State
+
+### Arbre d'état unique
+
+Vuex utilise un **arbre d'état unique**, c'est-à-dire que cet unique objet contient tout l'état au niveau applicatif et sert de « source de vérité unique ». Cela signifie également que vous n'aurez qu'un seul store pour chaque application. Un arbre d'état unique rend rapide la localisation d'une partie spécifique de l'état et permet de facilement prendre des instantanés de l'état actuel de l'application à des fins de débogage.
+
+L'arbre d'état unique n'entre pas en conflit avec la modularité. Dans les prochains chapitres, nous examinerons comment séparer votre état et vos mutations dans des sous-modules.
+
+### Récupération d'état Vuex dans des composants Vue
+
+Alors, comment affichons-nous l'état du store dans nos composants Vue ? Puisque les stores Vuex sont réactifs, la façon la plus simple d'y « récupérer » l'état est tout simplement de retourner une partie de l'état depuis une [une propriété calculée](https://fr.vuejs.org/guide/computed.html) :
+
+``` js
+// créons un composant Counter
+const Counter = {
+  template: `<div>{{ count }}</div>`,
+  computed: {
+    count () {
+      return store.state.count
+    }
+  }
+}
+```
+
+Lorsque `store.state.count` change, cela entrainera la réévaluation de la propriété calculée, et déclenchera les actions associées au DOM.
+
+Cependant, ce modèle oblige le composant à compter sur le singleton global du store. Lorsqu'on utilise un système de module, il est nécessaire d'importer le store dans tous les composants qui utilisent l'état du store, et il est également nécessaire de le simuler lorsque l'on teste le composant.
+
+Vuex fournit un mécanisme pour « injecter » le store dans tous les composants enfants du composant racine avec l'option `store` (activée par `Vue.use(Vuex)`) :
+
+``` js
+const app = new Vue({
+  el: '#app',
+  // fournit le store avec l'option `store`.
+  // cela injectera l'instance du store dans tous les composants enfants.
+  store,
+  components: { Counter },
+  template: `
+    <div class="app">
+      <counter></counter>
+    </div>
+  `
+})
+```
+
+En fournissant l'option `store` à l'instance racine, le store sera injecté dans tous les composants enfants de la racine et sera disponible dans ces derniers avec `this.$store`. Mettons à jour notre implémentation de `Counter` :
+
+``` js
+const Counter = {
+  template: `<div>{{ count }}</div>`,
+  computed: {
+    count () {
+      return this.$store.state.count
+    }
+  }
+}
+```
+
+### La fonction utilitaire `mapState`
+
+Lorsqu'un composant a besoin d'utiliser plusieurs accesseurs ou propriétés de l'état du store, déclarer toutes ces propriétés calculées peut devenir répétitif et verbeux. Afin de pallier à ça, nous pouvons utiliser la fonction utilitaire `mapState` qui génère des fonctions d'accession pour nous et nous épargne quelques coups de clavier :
+
+``` js
+// dans la version complète, des fonctions utilitaires sont exposées telles que `Vuex.mapState`
+import { mapState } from 'vuex'
+
+export default {
+  // ...
+  computed: mapState({
+    // les fonctions fléchées peuvent rendre le code très succinct !
+    count: state => state.count,
+
+    // passer la valeur littérale 'count' revient à écrire `state => state.count`
+    countAlias: 'count',
+
+    // pour accéder à l'état local avec `this`, une fonction normale doit être utilisée
+    countPlusLocalState (state) {
+      return state.count + this.localCount
+    }
+  })
+}
+```
+
+Il est également possible de fournir un tableau de chaines de caractères à `mapState` lorsque le nom de la propriété calculée associée est le même que le nom de l'état du store.
+
+``` js
+computed: mapState([
+  // attacher `this.count` à `store.state.count`
+  'count'
+])
+```
+
+### Opérateur de décomposition
+
+Notez que `mapState` renvoie un objet. Comment l'utiliser en complément des autres propriétés calculées locales ? Normalement, il faudrait utiliser un outil pour fusionner les multiples objets en un seul afin de passer cet objet final à `computed`. Cependant avec l'[opérateur de décomposition](https://github.com/sebmarkbage/ecmascript-rest-spread) (qui est une proposition stage-4 ECMASCript), nous pouvons grandement simplifier la syntaxe :
+
+``` js
+computed: {
+  localComputed () { /* ... */ },
+  // rajouter cet objet dans l'objet `computed` avec l'opérateur de décomposition
+  ...mapState({
+    // ...
+  })
+}
+```
+
+### Les composants peuvent toujours avoir un état local
+
+Utiliser Vuex ne signifie pas que vous devez mettre **tout** votre état dans Vuex. Bien que le fait de mettre plus d'états dans Vuex rende vos mutations d'état plus explicites et plus débogable, parfois il peut aussi rendre le code plus verbeux et indirect. Si une partie de l'état appartient directement à un seul composant, il est parfaitement sain de la laisser dans l'état local. Assurez-vous de prendre en compte les avantages et inconvénients d'une telle décision afin de vous adapter au mieux aux besoins de votre application.

+ 25 - 0
docs/fr/guide/strict.md

@@ -0,0 +1,25 @@
+# Mode strict
+
+Pour activer le mode strict, passez simplement l'option `strict: true` pendant la création d'un store Vuex :
+
+``` js
+const store = new Vuex.Store({
+  // ...
+  strict: true
+})
+```
+
+En mode strict, lorsque l'état de Vuex est modifié en dehors des gestionnaires de mutation, une erreur sera lancée. Cela permet de s'assurer que toutes les mutations de l'état peuvent être explicitement tracées par les outils de débogage.
+
+### Développement vs. production
+
+**N'activez pas le mode strict lorsque vous déployez en production !** Le mode strict lance une observation récursive de l'arbre d'état pour détecter des mutations inappropriées. Assurez-vous de l'avoir désactivé en production pour éviter un cout sur les performances.
+
+Tout comme les plugins, nous pouvons laisser nos outils de build gérer ça :
+
+``` js
+const store = new Vuex.Store({
+  // ...
+  strict: process.env.NODE_ENV !== 'production'
+})
+```

+ 32 - 0
docs/fr/guide/structure.md

@@ -0,0 +1,32 @@
+# Structure d'une application
+
+Vuex ne vous restreint pas quand à la structure de code à utiliser. Il impose plutôt de respecter des principes de haut niveau :
+
+1. L'état de l'application est centralisé dans le store.
+
+2. La seule façon de muter l'état est d'acter des **mutations**, qui sont des transactions synchrones.
+
+3. La logique asynchrone doit être composée et encapsulée dans des **actions**.
+
+Tant que vous suivez ces règles, c'est à vous de structurer votre projet. Si votre fichier de store devient trop gros, commencez dès lors à séparer les actions, mutations et accesseurs dans des fichiers séparés.
+
+Pour une application non triviale, nous aurons probablement besoin de faire appel à des modules. Voici un exemple de structure de projet :
+
+``` bash
+├── index.html
+├── main.js
+├── api
+│   └── ... # abstraction pour faire des requêtes par API
+├── components
+│   ├── App.vue
+│   └── ...
+└── store
+    ├── index.js          # là où l'on assemble nos modules et exportons le store
+    ├── actions.js        # actions racine
+    ├── mutations.js      # mutations racine
+    └── modules
+        ├── cart.js       # module de panier
+        └── products.js   # module de produit
+```
+
+Vous pouvez jeter à un œil à l'[exemple de panier d'achats](https://github.com/vuejs/vuex/tree/dev/examples/shopping-cart).

+ 238 - 0
docs/fr/guide/testing.md

@@ -0,0 +1,238 @@
+# Tests
+
+Les parties principales que l'on veut couvrir par des tests unitaires avec Vuex sont les mutations et les actions.
+
+### Tester les mutations
+
+Les mutations sont très simples à tester, puisque ce sont de simples fonctions qui se basent uniquement sur leurs arguments. Une astuce est que si vous utilisez les modules ES2015 et mettez vos mutations dans votre fichier `store.js`, en plus de l'export par défaut, vous pouvez également exporter vos mutations avec un export nommé :
+
+``` js
+const state = { ... }
+
+// exporter `mutations` en tant qu'export nommé
+export const mutations = { ... }
+
+export default new Vuex.Store({
+  state,
+  mutations
+})
+```
+
+Exemple de test de mutation utilisant Mocha + Chai (vous pouvez utiliser n'importe quel framework/bibliothèque d'assertion selon vos préférences) :
+
+``` js
+// mutations.js
+export const mutations = {
+  increment: state => state.count++
+}
+```
+
+``` js
+// mutations.spec.js
+import { expect } from 'chai'
+import { mutations } from './store'
+
+// assignement de `mutations` par déstructuration
+const { increment } = mutations
+
+describe('mutations', () => {
+  it('INCREMENT', () => {
+    // état simulé
+    const state = { count: 0 }
+    // appliquer la mutation
+    increment(state)
+    // tester le résultat
+    expect(state.count).to.equal(1)
+  })
+})
+```
+
+### Tester les actions
+
+Les actions sont un peu plus compliquées car elles peuvent faire appel à des APIs externes. Lorsque l'on teste des actions, on a souvent besoin de faire plusieurs niveaux de simulation. Par exemple, on peut abstraire l'appel API dans un service et simuler ce service dans nos tests. Afin de simuler facilement les dépendances, on peut utiliser webpack et [inject-loader](https://github.com/plasticine/inject-loader) pour regrouper nos fichiers de test.
+
+Exemple de test d'une action asynchrone :
+
+``` js
+// actions.js
+import shop from '../api/shop'
+
+export const getAllProducts = ({ commit }) => {
+  commit('REQUEST_PRODUCTS')
+  shop.getProducts(products => {
+    commit('RECEIVE_PRODUCTS', products)
+  })
+}
+```
+
+``` js
+// actions.spec.js
+
+// utilisation de la syntaxe `require` pour les loaders.
+// avec inject-loader, cela retourne un module de fabrique
+// cela nous permet d'injecter les dépendances simulées.
+import { expect } from 'chai'
+const actionsInjector = require('inject-loader!./actions')
+
+// créer un module avec nos simulations
+const actions = actionsInjector({
+  '../api/shop': {
+    getProducts (cb) {
+      setTimeout(() => {
+        cb([ /* réponse simulée */ ])
+      }, 100)
+    }
+  }
+})
+
+// fonction utilitaire pour tester des actions avec les mutations attendues
+const testAction = (action, args, state, expectedMutations, done) => {
+  let count = 0
+
+  // acter une simulation
+  const commit = (type, payload) => {
+    const mutation = expectedMutations[count]
+
+    try {
+      expect(mutation.type).to.equal(type)
+      if (payload) {
+        expect(payload).to.deep.equal(mutation.payload)
+      }
+    } catch (error) {
+      done(error)
+    }
+
+    count++
+    if (count >= expectedMutations.length) {
+      done()
+    }
+  }
+
+  // appeler l'action avec le store simulé et les arguments
+  action({ commit, state }, ...args)
+
+  // vérifier qu'aucune mutation n'ait été propagée
+  if (expectedMutations.length === 0) {
+    expect(count).to.equal(0)
+    done()
+  }
+}
+
+describe('actions', () => {
+  it('getAllProducts', done => {
+    testAction(actions.getAllProducts, [], {}, [
+      { type: 'REQUEST_PRODUCTS' },
+      { type: 'RECEIVE_PRODUCTS', payload: { /* mocked response */ } }
+    ], done)
+  })
+})
+```
+
+Si vous avez des espions disponibles dans votre environnement de test (par exemple via [Sinon.JS](http://sinonjs.org/)), vous pouvez les utiliser à la place de la fonction utilitaire `testAction` :
+
+``` js
+describe('actions', () => {
+  it('getAllProducts', () => {
+    const commit = sinon.spy()
+    const state = {}
+     actions.getAllProducts({ commit, state })
+     expect(commit.args).to.deep.equal([
+      ['REQUEST_PRODUCTS'],
+      ['RECEIVE_PRODUCTS', { /* réponse de la mockup */ }]
+    ])
+  })
+})
+```
+
+### Tester les accesseurs
+
+Si vos accesseurs font des calculs compliqués, il peut être judicieux de les tester. Les accesseurs sont également très simples à tester, pour les mêmes raisons que les mutations.
+
+Exemple de test d'un accesseur :
+
+``` js
+// getters.js
+export const getters = {
+  filteredProducts (state, { filterCategory }) {
+    return state.products.filter(product => {
+      return product.category === filterCategory
+    })
+  }
+}
+```
+
+``` js
+// getters.spec.js
+import { expect } from 'chai'
+import { getters } from './getters'
+
+describe('getters', () => {
+  it('filteredProducts', () => {
+    // état simulé
+    const state = {
+      products: [
+        { id: 1, title: 'Apple', category: 'fruit' },
+        { id: 2, title: 'Orange', category: 'fruit' },
+        { id: 3, title: 'Carrot', category: 'vegetable' }
+      ]
+    }
+    // accesseur simulé
+    const filterCategory = 'fruit'
+
+    // obtenir le résultat depuis l'accesseur
+    const result = getters.filteredProducts(state, { filterCategory })
+
+    // tester le résultat
+    expect(result).to.deep.equal([
+      { id: 1, title: 'Apple', category: 'fruit' },
+      { id: 2, title: 'Orange', category: 'fruit' }
+    ])
+  })
+})
+```
+
+### Lancer les tests
+
+Si vos mutations et actions sont écrites comme il se doit, les tests ne devraient pas avoir de dépendance directe sur les APIs navigateur après une simulation préalable. Cela signifie que vous pouvez simplement regrouper les tests avec webpack et les lancer directement dans Node.js. De façon alternative, vous pouvez utiliser `mocha-loader` ou Karma + `karma-webpack` afin d'effectuer les tests dans des vrais navigateurs.
+
+#### Lancer dans Node.js
+
+Créez la configuration webpack suivante (ainsi que le fichier [`.babelrc`](https://babeljs.io/docs/usage/babelrc/) qui correspond) :
+
+``` js
+// webpack.config.js
+module.exports = {
+  entry: './test.js',
+  output: {
+    path: __dirname,
+    filename: 'test-bundle.js'
+  },
+  module: {
+    loaders: [
+      {
+        test: /\.js$/,
+        loader: 'babel-loader',
+        exclude: /node_modules/
+      }
+    ]
+  }
+}
+```
+
+Puis :
+
+``` bash
+webpack
+mocha test-bundle.js
+```
+
+#### Lancer dans un navigateur
+
+1. Installez `mocha-loader`.
+2. Changez l'option `entry` de la configuration webpack ci-dessus pour `'mocha-loader!babel-loader!./test.js'`.
+3. Démarrez `webpack-dev-server` en utilisant la configuration.
+4. Rendez-vous avec votre navigateur sur `localhost:8080/webpack-dev-server/test-bundle`.
+
+#### Lancer dans un navigateur avec Karma + karma-webpack
+
+Consultez la procédure sur la [documentation vue-loader](https://vue-loader.vuejs.org/en/workflow/testing.html).

+ 74 - 0
docs/fr/installation.md

@@ -0,0 +1,74 @@
+# Installation
+
+### Téléchargement direct / CDN
+
+[https://unpkg.com/vuex](https://unpkg.com/vuex)
+
+<!--email_off-->
+[Unpkg.com](https://unpkg.com) fournit des liens CDN basés sur npm. Le lien ci-dessus pointera toujours vers la dernière release sur npm. Vous pouvez aussi utiliser un tag ou une version spécifique via un URL comme `https://unpkg.com/vuex@2.0.0`.
+<!--/email_off-->
+
+Incluez `vuex` après Vue et l'installation sera automatique :
+
+``` html
+<script src="/path/to/vue.js"></script>
+<script src="/path/to/vuex.js"></script>
+```
+
+### npm
+
+``` bash
+npm install vuex --save
+```
+
+### Yarn
+
+``` bash
+yarn add vuex
+```
+
+Lorsqu'il est utilisé avec un système de module, vous devez explicitement installer Vuex via `Vue.use()`:
+
+``` js
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+Vue.use(Vuex)
+```
+
+Vous n'avez pas besoin de faire cela lors de l'utilisation des balises de script globales (`<script>`).
+
+### Promesse
+Vuex nécessite les [promesses](https://developer.mozilla.org/fr/docs/Web/JavaScript/Guide/Utiliser_les_promesses). Si vous supporter des navigateurs qui n'implémentent pas les promesses (par ex. IE), vous devez utiliser une bibliothèque polyfill, comme [es6-promise](https://github.com/stefanpenner/es6-promise).
+
+Vous pouvez l'inclure par CDN :
+
+``` html
+<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.js"></script>
+```
+
+Puis `window.Promise` sera disponible automatiquement.
+
+Si vous préférez utiliser un gestionnaire de package comme npm ou Yarn, installez le avec les commandes suivantes :
+
+``` bash
+npm install es6-promise --save # NPM
+yarn add es6-promise # Yarn
+```
+
+Puis, ajoutez la ligne ci-dessous partout dans votre code juste avant l'utilisation de Vuex :
+
+``` js
+import 'es6-promise/auto'
+```
+
+### Build de développement
+
+Vous aurez besoin de cloner directement vuex depuis GitHub et le compiler vous-même si vous souhaitez utiliser le dernier build de développement.
+
+``` bash
+git clone https://github.com/vuejs/vuex.git node_modules/vuex
+cd node_modules/vuex
+npm install
+npm run build
+```