Selaa lähdekoodia

添加i18n插件

Lijy 2 vuotta sitten
vanhempi
commit
c7293bdfca
37 muutettua tiedostoa jossa 14288 lisäystä ja 39 poistoa
  1. 1930 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/CHANGELOG.md
  2. 20 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/LICENSE
  3. 147 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/README.md
  4. 170 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/decls/i18n.js
  5. 30 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/decls/module.js
  6. 16 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/dist/README.md
  7. 2267 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/dist/vue-i18n.common.js
  8. 2216 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/dist/vue-i18n.esm.browser.js
  9. 1 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/dist/vue-i18n.esm.browser.min.js
  10. 2265 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/dist/vue-i18n.esm.js
  11. 2273 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/dist/vue-i18n.js
  12. 6 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/dist/vue-i18n.min.js
  13. 175 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/package.json
  14. 101 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/components/interpolation.js
  15. 70 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/components/number.js
  16. 112 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/directive.js
  17. 33 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/extend.js
  18. 114 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/format.js
  19. 1120 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/index.js
  20. 40 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/install.js
  21. 159 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/mixin.js
  22. 302 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/path.js
  23. 209 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/util.js
  24. 295 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/types/index.d.ts
  25. 34 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/vetur/attributes.json
  26. 20 0
      fhKeeper/formulahousekeeper/node_modules/vue-i18n/vetur/tags.json
  27. 11 0
      fhKeeper/formulahousekeeper/package-lock.json
  28. 13 11
      fhKeeper/formulahousekeeper/timesheet/config/index.js
  29. 11 6
      fhKeeper/formulahousekeeper/timesheet/package-lock.json
  30. 1 0
      fhKeeper/formulahousekeeper/timesheet/package.json
  31. 18 0
      fhKeeper/formulahousekeeper/timesheet/src/i18n/en.js
  32. 20 0
      fhKeeper/formulahousekeeper/timesheet/src/i18n/index.js
  33. 9 0
      fhKeeper/formulahousekeeper/timesheet/src/i18n/zh.js
  34. 4 0
      fhKeeper/formulahousekeeper/timesheet/src/main.js
  35. 28 9
      fhKeeper/formulahousekeeper/timesheet/src/routes.js
  36. 38 3
      fhKeeper/formulahousekeeper/timesheet/src/views/Home.vue
  37. 10 10
      fhKeeper/formulahousekeeper/timesheet_h5/vue.config.js

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1930 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/CHANGELOG.md


+ 20 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/LICENSE

@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 kazuya kawaguchi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 147 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/README.md

@@ -0,0 +1,147 @@
+<p align="center"><img width="128px" height="112px" src="./assets/vue-i18n-logo.png" alt="Vue I18n logo"></p>
+<h1 align="center">vue-i18n</h1>
+<p align="center">
+  <a href="https://circleci.com/gh/kazupon/vue-i18n/tree/dev"><img src="https://circleci.com/gh/kazupon/vue-i18n/tree/dev.svg?style=shield" alt="Build Status"></a>
+  <a href="http://badge.fury.io/js/vue-i18n"><img src="https://badge.fury.io/js/vue-i18n.svg" alt="NPM version"></a>
+  <a href="https://discord.gg/4yCnk2m"><img src="https://img.shields.io/badge/Discord-join%20chat-738bd7.svg" alt="vue-i18n channel on Discord"></a>
+</p>
+
+<p align="center">Internationalization plugin for Vue.js</p>
+
+<br/>
+
+<h3 align="center">🏅 Platinum Sponsors</h3>
+
+<p align="center">
+  <a href="https://zenarchitects.co.jp/" target="_blank">
+    <img
+      src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/zenarchitects.png"
+      width="400px"
+    />
+  </a>
+</p>
+
+<h3 align="center">✨ Special Sponsors</h3>
+
+<p align="center">
+  <a
+    href="https://plaid.co.jp/"
+    target="_blank">
+    <img
+      src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/plaid.svg"
+      width="240px"
+    />
+  </a>
+</p>
+
+<h3 align="center">🥇 Gold Sponsors</h3>
+
+<p align="center">
+  <a
+    href="https://nuxtjs.org/"
+    target="_blank">
+    <img
+      src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/nuxt.png"
+      width="240px"
+    />
+  </a>
+</p>
+
+<p align="center">
+  <a
+    href="https://rapidapi.com/"
+    target="_blank">
+    <img
+      src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/RapidAPI.svg"
+      width="240px"
+    />
+  </a>
+</p>
+
+<p align="center">
+  <a
+    href="https://localazy.com/blog/how-to-localize-vuejs-app-with-vue-i18n-and-localazy?utm_source=kazupon&utm_medium=banner&utm_campaign=sponsorships_kazupon&utm_content=logo"
+    target="_blank">
+    <img
+      src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/localazy.svg"
+      width="240px"
+    />
+  </a>
+</p>
+
+<p align="center">
+  <a 
+    href="https://crowdin.com/teams/engineering?utm_source=vue-i18n.intlify.dev&utm_medium=referral"
+    target="_blank">
+    <img
+      src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/crowdin.svg"
+      width="240px"
+    />
+  </a>
+</p>
+
+<h3 align="center">🥈 Silver Sponsors</h3>
+
+<h3 align="center">🥉 Bronze Sponsors</h3>
+
+<p align="center">
+  <a href="https://www.sendcloud.com/" target="_blank">
+    <img
+      src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/sendcloud.png"
+      width="144px"
+    />
+  </a>
+</p>
+<p align="center">
+  <a href="https://www.vuemastery.com/" target="_blank">
+    <img
+      src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/vuemastery.png"
+      width="144px"
+    />
+  </a>
+</p>
+<p align="center">
+  <a href="https://www.deci-bel.com/" target="_blank">
+    <img
+      src="https://raw.githubusercontent.com/kazupon/vue-i18n/v8.x/vuepress/.vuepress/public/patrons/decibel.png"
+      width="144px"
+    />
+  </a>
+</p>
+
+<br/>
+
+## ⚠️  NOTICE
+
+**This repository is for Vue I18n v8.x and Vue 2**
+
+**If you want to know about how to usage for Vue I18n v9 on Vue 3, See the [this repository](https://github.com/intlify/vue-i18n-next))**
+
+## 🙋‍♂️ About support for v8
+
+We will follow Vue v2 maintenance lifespan
+
+## 📔 Documentation
+
+About Vue I18n v8.x, See [here](http://kazupon.github.io/vue-i18n/)
+
+If you want to read Vue I18n v9 docs, See [here](https://vue-i18n.intlify.dev/)
+
+## 📜 Changelog
+
+Detailed changes for each release are documented in the [CHANGELOG.md](https://github.com/kazupon/vue-i18n/blob/dev/CHANGELOG.md).
+
+
+## ❗ Issues
+
+Please make sure to read the [Issue Reporting Checklist](https://github.com/kazupon/vue-i18n/blob/dev/CONTRIBUTING.md#issue-reporting-guidelines) before opening an issue. Issues not conforming to the guidelines may be closed immediately.
+
+
+## 💪 Contribution
+
+Please make sure to read the [Contributing Guide](https://github.com/kazupon/vue-i18n/blob/dev/CONTRIBUTING.md) before making a pull request.
+
+
+## ©️ License
+
+[MIT](http://opensource.org/licenses/MIT)

+ 170 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/decls/i18n.js

@@ -0,0 +1,170 @@
+declare var Intl: any;
+
+declare type Path = string;
+declare type Locale = string;
+declare type MessageContext = {
+  list: (index: number) => mixed,
+  named: (key: string) => mixed,
+  linked: (key: string) => TranslateResult,
+  values: any,
+  path: string,
+  formatter: Formatter,
+  messages: LocaleMessages,
+  locale: Locale
+}
+declare type MessageFunction = (ctx: MessageContext) => string
+declare type FallbackLocale = string | string[] | false | { [locale: string]: string[] };
+declare type LocaleMessage = string | MessageFunction | LocaleMessageObject | LocaleMessageArray;
+declare type LocaleMessageObject = { [key: Path]: LocaleMessage };
+declare type LocaleMessageArray = Array<LocaleMessage>;
+declare type LocaleMessages = { [key: Locale]: LocaleMessageObject };
+
+// This options is the same as Intl.DateTimeFormat constructor options:
+// http://www.ecma-international.org/ecma-402/2.0/#sec-intl-datetimeformat-constructor
+declare type DateTimeFormatOptions = {
+  year?: 'numeric' | '2-digit',
+  month?: 'numeric' | '2-digit' | 'narrow' | 'short' | 'long',
+  day?: 'numeric' | '2-digit',
+  hour?: 'numeric' | '2-digit',
+  minute?: 'numeric' | '2-digit',
+  second?: 'numeric' | '2-digit',
+  weekday?: 'narrow' | 'short' | 'long',
+  hour12?: boolean,
+  era?: 'narrow' | 'short' | 'long',
+  timeZone?: string, // IANA time zone
+  timeZoneName?: 'short' | 'long',
+  localeMatcher?: 'lookup' | 'best fit',
+  formatMatcher?: 'basic' | 'best fit'
+};
+declare type DateTimeFormat = { [key: string]: DateTimeFormatOptions };
+declare type DateTimeFormats = { [key: Locale]: DateTimeFormat };
+
+// This options is the same as Intl.NumberFormat constructor options:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat
+declare type NumberFormatOptions = {
+  style?: 'decimal' | 'currency' | 'percent',
+  currency?: string, // ISO 4217 currency codes
+  currencyDisplay?: 'symbol' | 'code' | 'name',
+  useGrouping?: boolean,
+  minimumIntegerDigits?: number,
+  minimumFractionDigits?: number,
+  maximumFractionDigits?: number,
+  minimumSignificantDigits?: number,
+  maximumSignificantDigits?: number,
+  localeMatcher?: 'lookup' | 'best fit',
+  formatMatcher?: 'basic' | 'best fit'
+};
+declare type NumberFormat = { [key: string]: NumberFormatOptions };
+declare type NumberFormats = { [key: Locale]: NumberFormat };
+declare type Modifiers = { [key: string]: (str: string) => string };
+
+declare type TranslateResult = string | LocaleMessages;
+declare type DateTimeFormatResult = string;
+declare type NumberFormatResult = string;
+declare type MissingHandler = (locale: Locale, key: Path, vm?: any) => string | void;
+declare type PostTranslationHandler = (str: string, key?: string) => string;
+declare type GetChoiceIndex = (choice: number, choicesLength: number) => number
+declare type ComponentInstanceCreatedListener = (newI18n: I18n, rootI18n: I18n) => void;
+
+declare type FormattedNumberPartType = 'currency' | 'decimal' | 'fraction' | 'group' | 'infinity' | 'integer' | 'literal' | 'minusSign' | 'nan' | 'plusSign' | 'percentSign';
+declare type FormattedNumberPart = {
+  type: FormattedNumberPartType,
+  value: string,
+};
+// This array is the same as Intl.NumberFormat.formatToParts() return value:
+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat/formatToParts#Return_value
+declare type NumberFormatToPartsResult = Array<FormattedNumberPart>;
+
+declare type WarnHtmlInMessageLevel = 'off' | 'warn' | 'error';
+
+declare type I18nOptions = {
+  locale?: Locale,
+  fallbackLocale?: FallbackLocale,
+  messages?: LocaleMessages,
+  dateTimeFormats?: DateTimeFormats,
+  datetimeFormats?: DateTimeFormats,
+  numberFormats?: NumberFormats,
+  formatter?: Formatter,
+  missing?: MissingHandler,
+  modifiers?: Modifiers,
+  root?: I18n, // for internal
+  fallbackRoot?: boolean,
+  fallbackRootWithEmptyString?: boolean,
+  formatFallbackMessages?: boolean,
+  sync?: boolean,
+  silentTranslationWarn?: boolean | RegExp,
+  silentFallbackWarn?: boolean | RegExp,
+  pluralizationRules?: PluralizationRules,
+  preserveDirectiveContent?: boolean,
+  warnHtmlInMessage?: WarnHtmlInMessageLevel,
+  sharedMessages?: LocaleMessage,
+  postTranslation?: PostTranslationHandler,
+  componentInstanceCreatedListener?: ComponentInstanceCreatedListener,
+  escapeParameterHtml?: boolean,
+  __VUE_I18N_BRIDGE__?: string,
+};
+
+declare type IntlAvailability = {
+  dateTimeFormat: boolean,
+  numberFormat: boolean
+};
+
+declare type PluralizationRules = {
+  [lang: string]: GetChoiceIndex,
+}
+
+declare interface I18n {
+  static install: () => void, // for Vue plugin interface
+  static version: string,
+  static availabilities: IntlAvailability,
+  get vm (): any, // for internal
+  get locale (): Locale,
+  set locale (locale: Locale): void,
+  get fallbackLocale (): FallbackLocale,
+  set fallbackLocale (locale: FallbackLocale): void,
+  get messages (): LocaleMessages,
+  get dateTimeFormats (): DateTimeFormats,
+  get numberFormats (): NumberFormats,
+  get availableLocales (): Locale[],
+  get missing (): ?MissingHandler,
+  set missing (handler: MissingHandler): void,
+  get formatter (): Formatter,
+  set formatter (formatter: Formatter): void,
+  get formatFallbackMessages (): boolean,
+  set formatFallbackMessages (fallback: boolean): void,
+  get silentTranslationWarn (): boolean | RegExp,
+  set silentTranslationWarn (silent: boolean | RegExp): void,
+  get silentFallbackWarn (): boolean | RegExp,
+  set silentFallbackWarn (slient: boolean | RegExp): void,
+  get pluralizationRules (): PluralizationRules,
+  set pluralizationRules (rules: PluralizationRules): void,
+  get preserveDirectiveContent (): boolean,
+  set preserveDirectiveContent (preserve: boolean): void,
+  get warnHtmlInMessage (): WarnHtmlInMessageLevel,
+  set warnHtmlInMessage (level: WarnHtmlInMessageLevel): void,
+  get postTranslation (): ?PostTranslationHandler,
+  set postTranslation (handler: PostTranslationHandler): void,
+
+  getLocaleMessage (locale: Locale): LocaleMessageObject,
+  setLocaleMessage (locale: Locale, message: LocaleMessageObject): void,
+  mergeLocaleMessage (locale: Locale, message: LocaleMessageObject): void,
+  t (key: Path, ...values: any): TranslateResult,
+  i (key: Path, locale: Locale, values: Object): TranslateResult,
+  tc (key: Path, choice?: number, ...values: any): TranslateResult,
+  te (key: Path, locale?: Locale): boolean,
+  getDateTimeFormat (locale: Locale): DateTimeFormat,
+  setDateTimeFormat (locale: Locale, format: DateTimeFormat): void,
+  mergeDateTimeFormat (locale: Locale, format: DateTimeFormat): void,
+  d (value: number | Date, ...args: any): DateTimeFormatResult,
+  getNumberFormat (locale: Locale): NumberFormat,
+  setNumberFormat (locale: Locale, format: NumberFormat): void,
+  mergeNumberFormat (locale: Locale, format: NumberFormat): void,
+  n (value: number, ...args: any): NumberFormatResult,
+  getChoiceIndex: GetChoiceIndex,
+  pluralizationRules: PluralizationRules,
+  preserveDirectiveContent: boolean
+};
+
+declare interface Formatter {
+  interpolate (message: string, values: any, path: string): (Array<any> | null)
+};

+ 30 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/decls/module.js

@@ -0,0 +1,30 @@
+declare type $npm$Vue$Dictionaly<T> = { [key: string]: T }
+
+declare type Util = {
+  extend: (to: Object, from: ?Object) => Object,
+  hasOwn: (obj: Object, key: string) => boolean,
+  isPlainObject: (obj: any) => boolean,
+  isObject: (obj: mixed) => boolean,
+}
+
+declare type Config = {
+  optionMergeStrategies: $npm$Vue$Dictionaly<Function>,
+  silent: boolean,
+  productionTip: boolean,
+  performance: boolean,
+  devtools: boolean,
+  errorHandler: ?(err: Error, vm: Vue, info: string) => void,
+  ignoredElements: Array<string>,
+  keyCodes: $npm$Vue$Dictionaly<number>,
+  isReservedTag: (x?: string) => boolean,
+  parsePlatformTagName: (x: string) => string,
+  isUnknownElement: (x?: string) => boolean,
+  getTagNamespace: (x?: string) => string | void,
+  mustUseProp: (tag: string, type: ?string, name: string) => boolean,
+}
+
+declare interface Vue {
+  static config: Config,
+  static util: Util,
+  static version: string,
+}

+ 16 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/dist/README.md

@@ -0,0 +1,16 @@
+## Explanation of Different Builds
+
+- UMD: `vue-i18n.js`
+- CommonJS: `vue-i18n.common.js`
+- ES Module for bundlers: `vue-i18n.esm.js`
+- ES Module for browsers: `vue-i18n.esm.browser.js`
+
+### Terms
+
+- **[UMD](https://github.com/umdjs/umd)**: UMD builds can be used directly in the browser via a `<script>` tag. The default file from Unpkg CDN at [https://unpkg.com/vue-i18n](https://unpkg.com/vue-i18n) is the UMD build (`vue-i18n.js`).
+
+- **[CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1)**: CommonJS builds are intended for use with older bundlers like [browserify](http://browserify.org/) or [webpack 1](https://webpack.github.io). The default file for these bundlers (`pkg.main`) is the Runtime only CommonJS build (`vue-i18n.common.js`).
+
+- **[ES Module](http://exploringjs.com/es6/ch_modules.html)**: starting in 8.11 VueI18n provides two ES Modules (ESM) builds:
+  - ESM for bundlers: intended for use with modern bundlers like [webpack 2](https://webpack.js.org) or [Rollup](https://rollupjs.org/). ESM format is designed to be statically analyzable so the bundlers can take advantage of that to perform "tree-shaking" and eliminate unused code from your final bundle. The default file for these bundlers (`pkg.module`) is the Runtime only ES Module build (`vue-i18n.esm.js`).
+  - ESM for browsers (8.11+ only, `vue-i18n.esm.browser.js`): intended for direct imports in modern browsers via `<script type="module">`.

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2267 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/dist/vue-i18n.common.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2216 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/dist/vue-i18n.esm.browser.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/dist/vue-i18n.esm.browser.min.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2265 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/dist/vue-i18n.esm.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 2273 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/dist/vue-i18n.js


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 6 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/dist/vue-i18n.min.js


+ 175 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/package.json

@@ -0,0 +1,175 @@
+{
+  "_from": "vue-i18n@8",
+  "_id": "vue-i18n@8.27.2",
+  "_inBundle": false,
+  "_integrity": "sha512-QVzn7u2WVH8F7eSKIM00lujC7x1mnuGPaTnDTmB01Hd709jDtB9kYtBqM+MWmp5AJRx3gnqAdZbee9MelqwFBg==",
+  "_location": "/vue-i18n",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "range",
+    "registry": true,
+    "raw": "vue-i18n@8",
+    "name": "vue-i18n",
+    "escapedName": "vue-i18n",
+    "rawSpec": "8",
+    "saveSpec": null,
+    "fetchSpec": "8"
+  },
+  "_requiredBy": [
+    "#USER",
+    "/"
+  ],
+  "_resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.27.2.tgz",
+  "_shasum": "b649a65ff42b7d1a482679b732902f889965a068",
+  "_spec": "vue-i18n@8",
+  "_where": "D:\\工作\\火石\\manHourHousekeeper\\fhKeeper\\formulahousekeeper",
+  "author": {
+    "name": "kazuya kawaguchi",
+    "email": "kawakazu80@gmail.com"
+  },
+  "bugs": {
+    "url": "https://github.com/kazupon/vue-i18n/issues"
+  },
+  "bundleDependencies": false,
+  "changelog": {
+    "labels": {
+      "Type: Feature": ":star: New Features",
+      "Type: Bug": ":bug: Bug Fixes",
+      "Type: Security": ":lock: Security Fixes",
+      "Type: Performance": ":chart_with_upwards_trend: Performance Fixes",
+      "Type: Improvement": ":zap: Improved Features",
+      "Type: Breaking": ":boom: Breaking Change",
+      "Type: Deprecated": ":warning: Deprecated Features",
+      "Type: I18n": ":globe_with_meridians: Internationalization",
+      "Type: A11y": ":wheelchair: Accessibility",
+      "Type: Documentation": ":pencil: Documentation"
+    }
+  },
+  "deprecated": false,
+  "description": "Internationalization plugin for Vue.js",
+  "devDependencies": {
+    "@babel/core": "^7.1.0",
+    "@babel/plugin-proposal-class-properties": "^7.1.0",
+    "@babel/plugin-syntax-flow": "^7.0.0",
+    "@babel/plugin-transform-flow-strip-types": "^7.0.0",
+    "@typescript-eslint/eslint-plugin": "^3.0.0",
+    "@typescript-eslint/parser": "^3.0.0",
+    "@vue/babel-preset-app": "^4.4.1",
+    "@vuepress/theme-vue": "^1.9.7",
+    "babel-eslint": "^10.1.0",
+    "babel-loader": "^8.1.0",
+    "babel-plugin-istanbul": "^6.0.0",
+    "babel-preset-power-assert": "^3.0.0",
+    "buble": "^0.19.3",
+    "chromedriver": "^102.0.0",
+    "core-js": "^3.6.5",
+    "cross-env": "^7.0.2",
+    "cross-spawn": "^7.0.3",
+    "eslint": "^6.8.0",
+    "eslint-loader": "^4.0.2",
+    "eslint-plugin-flowtype": "^4.7.0",
+    "eslint-plugin-ie11": "^1.0.0",
+    "eslint-plugin-no-autofix": "^1.0.1",
+    "eslint-plugin-vue": "^7.14.0",
+    "eslint-plugin-vue-libs": "^4.0.0",
+    "flow-bin": "^0.38.0",
+    "http-server": "^0.12.3",
+    "intl": "^1.2.5",
+    "karma": "^5.0.9",
+    "karma-chrome-launcher": "^3.1.0",
+    "karma-coverage": "^2.0.2",
+    "karma-firefox-launcher": "^2.1.1",
+    "karma-mocha": "^2.0.1",
+    "karma-mocha-reporter": "^2.2.5",
+    "karma-safari-launcher": "^1.0.0",
+    "karma-sauce-launcher": "^4.1.5",
+    "karma-sourcemap-loader": "^0.3.7",
+    "karma-webpack": "^4.0.2",
+    "lerna-changelog": "^1.0.0",
+    "lerna-changelog-label-schema": "^3.0.0",
+    "mocha": "^7.2.0",
+    "mocha-loader": "^5.0.0",
+    "nightwatch": "^1.3.5",
+    "nightwatch-helpers": "^1.2.0",
+    "power-assert": "^1.6.0",
+    "rollup": "^0.66.0",
+    "rollup-plugin-buble": "^0.19.2",
+    "rollup-plugin-commonjs": "^9.1.8",
+    "rollup-plugin-flow-no-whitespace": "^1.0.0",
+    "rollup-plugin-node-resolve": "^3.4.0",
+    "rollup-plugin-replace": "^2.0.0",
+    "selenium-server": "^3.141.59",
+    "shipjs": "^0.23.3",
+    "sinon": "^11.1.1",
+    "terser": "^3.17.0",
+    "typescript": "^3.9.3",
+    "vue": "^2.5.17",
+    "vue-github-button": "^1.1.2",
+    "vue-template-compiler": "^2.5.17",
+    "vuepress": "^1.8.2",
+    "webpack": "^4.43.0",
+    "webpack-cli": "^4.7.2",
+    "webpack-dev-middleware": "^5.0.0",
+    "webpack-dev-server": "^3.11.0"
+  },
+  "files": [
+    "dist/vue-i18n.js",
+    "dist/vue-i18n.min.js",
+    "dist/vue-i18n.common.js",
+    "dist/vue-i18n.esm.js",
+    "dist/vue-i18n.esm.browser.js",
+    "dist/vue-i18n.esm.browser.min.js",
+    "src/**/*.js",
+    "types/*.d.ts",
+    "decls",
+    "vetur/tags.json",
+    "vetur/attributes.json"
+  ],
+  "homepage": "https://github.com/kazupon/vue-i18n#readme",
+  "keywords": [
+    "i18n",
+    "internationalization",
+    "plugin",
+    "vue",
+    "vue.js"
+  ],
+  "license": "MIT",
+  "main": "dist/vue-i18n.common.js",
+  "module": "dist/vue-i18n.esm.js",
+  "name": "vue-i18n",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/kazupon/vue-i18n.git"
+  },
+  "scripts": {
+    "build": "node config/build.js",
+    "clean": "rm -rf coverage && rm -rf dist/*.js* && rm ./*.log",
+    "coverage": "cat ./coverage/lcov.info",
+    "dev": "cross-env BABEL_ENV=test webpack-dev-server --inline --hot --open --content-base ./test/unit/ --config config/webpack.dev.conf.js",
+    "docs:build": "cross-env NODE_ENV=production node config/version.js && cross-env NODE_ENV=production vuepress build vuepress -d docs",
+    "docs:clean": "rm -rf docs/**",
+    "docs:dev": "vuepress dev vuepress",
+    "flow": "flow check",
+    "lint": "eslint --fix src test types/**/*.ts",
+    "release:prepare": "shipjs prepare",
+    "release:trigger": "shipjs trigger",
+    "sauce": "npm run sauce:coolkids && npm run sauce:ie && npm run sauce:mobile",
+    "sauce:coolkids": "karma start config/karma.sauce.conf.js -- 0",
+    "sauce:ie": "karma start config/karma.sauce.conf.js -- 1",
+    "sauce:mobile": "karma start config/karma.sauce.conf.js -- 2",
+    "test": "npm run lint && npm run flow && npm run test:types && npm run test:cover && npm run test:e2e",
+    "test:cover": "cross-env BABEL_ENV=test karma start config/karma.cover.conf.js",
+    "test:e2e": "npm run build && node test/e2e/runner.js",
+    "test:types": "tsc -p types",
+    "test:unit": "cross-env BABEL_ENV=test karma start config/karma.unit.conf.js",
+    "test:unit:ci": "cross-env BABEL_ENV=test karma start config/karma.unit.ci.conf.js"
+  },
+  "sideEffects": false,
+  "types": "types/index.d.ts",
+  "unpkg": "dist/vue-i18n.js",
+  "version": "8.27.2",
+  "vetur": {
+    "tags": "vetur/tags.json",
+    "attributes": "vetur/attributes.json"
+  }
+}

+ 101 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/components/interpolation.js

@@ -0,0 +1,101 @@
+/* @flow */
+
+import { warn } from '../util'
+
+export default {
+  name: 'i18n',
+  functional: true,
+  props: {
+    tag: {
+      type: [String, Boolean, Object],
+      default: 'span'
+    },
+    path: {
+      type: String,
+      required: true
+    },
+    locale: {
+      type: String
+    },
+    places: {
+      type: [Array, Object]
+    }
+  },
+  render (h: Function, { data, parent, props, slots }: Object) {
+    const { $i18n } = parent
+    if (!$i18n) {
+      if (process.env.NODE_ENV !== 'production') {
+        warn('Cannot find VueI18n instance!')
+      }
+      return
+    }
+
+    const { path, locale, places } = props
+    const params = slots()
+    const children = $i18n.i(
+      path,
+      locale,
+      onlyHasDefaultPlace(params) || places
+        ? useLegacyPlaces(params.default, places)
+        : params
+    )
+
+    const tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span'
+    return tag ? h(tag, data, children) : children
+  }
+}
+
+function onlyHasDefaultPlace (params) {
+  let prop
+  for (prop in params) {
+    if (prop !== 'default') { return false }
+  }
+  return Boolean(prop)
+}
+
+function useLegacyPlaces (children, places) {
+  const params = places ? createParamsFromPlaces(places) : {}
+
+  if (!children) { return params }
+
+  // Filter empty text nodes
+  children = children.filter(child => {
+    return child.tag || child.text.trim() !== ''
+  })
+
+  const everyPlace = children.every(vnodeHasPlaceAttribute)
+  if (process.env.NODE_ENV !== 'production' && everyPlace) {
+    warn('`place` attribute is deprecated in next major version. Please switch to Vue slots.')
+  }
+
+  return children.reduce(
+    everyPlace ? assignChildPlace : assignChildIndex,
+    params
+  )
+}
+
+function createParamsFromPlaces (places) {
+  if (process.env.NODE_ENV !== 'production') {
+    warn('`places` prop is deprecated in next major version. Please switch to Vue slots.')
+  }
+
+  return Array.isArray(places)
+    ? places.reduce(assignChildIndex, {})
+    : Object.assign({}, places)
+}
+
+function assignChildPlace (params, child) {
+  if (child.data && child.data.attrs && child.data.attrs.place) {
+    params[child.data.attrs.place] = child
+  }
+  return params
+}
+
+function assignChildIndex (params, child, index) {
+  params[index] = child
+  return params
+}
+
+function vnodeHasPlaceAttribute (vnode) {
+  return Boolean(vnode.data && vnode.data.attrs && vnode.data.attrs.place)
+}

+ 70 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/components/number.js

@@ -0,0 +1,70 @@
+/* @flow */
+
+import { warn, isString, isObject, includes, numberFormatKeys } from '../util'
+
+export default {
+  name: 'i18n-n',
+  functional: true,
+  props: {
+    tag: {
+      type: [String, Boolean, Object],
+      default: 'span'
+    },
+    value: {
+      type: Number,
+      required: true
+    },
+    format: {
+      type: [String, Object]
+    },
+    locale: {
+      type: String
+    }
+  },
+  render (h: Function, { props, parent, data }: Object) {
+    const i18n = parent.$i18n
+
+    if (!i18n) {
+      if (process.env.NODE_ENV !== 'production') {
+        warn('Cannot find VueI18n instance!')
+      }
+      return null
+    }
+
+    let key: ?string = null
+    let options: ?NumberFormatOptions = null
+
+    if (isString(props.format)) {
+      key = props.format
+    } else if (isObject(props.format)) {
+      if (props.format.key) {
+        key = props.format.key
+      }
+
+      // Filter out number format options only
+      options = Object.keys(props.format).reduce((acc, prop) => {
+        if (includes(numberFormatKeys, prop)) {
+          return Object.assign({}, acc, { [prop]: props.format[prop] })
+        }
+        return acc
+      }, null)
+    }
+
+    const locale: Locale = props.locale || i18n.locale
+    const parts: NumberFormatToPartsResult = i18n._ntp(props.value, locale, key, options)
+
+    const values = parts.map((part, index) => {
+      const slot: ?Function = data.scopedSlots && data.scopedSlots[part.type]
+      return slot ? slot({ [part.type]: part.value, index, parts }) : part.value
+    })
+
+    const tag = (!!props.tag && props.tag !== true) || props.tag === false ? props.tag : 'span'
+    return tag
+      ? h(tag, {
+        attrs: data.attrs,
+        'class': data['class'],
+        staticClass: data.staticClass
+      }, values)
+      : values
+  }
+}

+ 112 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/directive.js

@@ -0,0 +1,112 @@
+/* @flow */
+
+import { warn, isString, isPlainObject, looseEqual } from './util'
+
+export function bind (el: any, binding: Object, vnode: any): void {
+  if (!assert(el, vnode)) { return }
+
+  t(el, binding, vnode)
+}
+
+export function update (el: any, binding: Object, vnode: any, oldVNode: any): void {
+  if (!assert(el, vnode)) { return }
+
+  const i18n: any = vnode.context.$i18n
+  if (localeEqual(el, vnode) &&
+    (looseEqual(binding.value, binding.oldValue) &&
+     looseEqual(el._localeMessage, i18n.getLocaleMessage(i18n.locale)))) { return }
+
+  t(el, binding, vnode)
+}
+
+export function unbind (el: any, binding: Object, vnode: any, oldVNode: any): void {
+  const vm: any = vnode.context
+  if (!vm) {
+    warn('Vue instance does not exists in VNode context')
+    return
+  }
+
+  const i18n: any = vnode.context.$i18n || {}
+  if (!binding.modifiers.preserve && !i18n.preserveDirectiveContent) {
+    el.textContent = ''
+  }
+  el._vt = undefined
+  delete el['_vt']
+  el._locale = undefined
+  delete el['_locale']
+  el._localeMessage = undefined
+  delete el['_localeMessage']
+}
+
+function assert (el: any, vnode: any): boolean {
+  const vm: any = vnode.context
+  if (!vm) {
+    warn('Vue instance does not exists in VNode context')
+    return false
+  }
+
+  if (!vm.$i18n) {
+    warn('VueI18n instance does not exists in Vue instance')
+    return false
+  }
+
+  return true
+}
+
+function localeEqual (el: any, vnode: any): boolean {
+  const vm: any = vnode.context
+  return el._locale === vm.$i18n.locale
+}
+
+function t (el: any, binding: Object, vnode: any): void {
+  const value: any = binding.value
+
+  const { path, locale, args, choice } = parseValue(value)
+  if (!path && !locale && !args) {
+    warn('value type not supported')
+    return
+  }
+
+  if (!path) {
+    warn('`path` is required in v-t directive')
+    return
+  }
+
+  const vm: any = vnode.context
+  if (choice != null) {
+    el._vt = el.textContent = vm.$i18n.tc(path, choice, ...makeParams(locale, args))
+  } else {
+    el._vt = el.textContent = vm.$i18n.t(path, ...makeParams(locale, args))
+  }
+  el._locale = vm.$i18n.locale
+  el._localeMessage = vm.$i18n.getLocaleMessage(vm.$i18n.locale)
+}
+
+function parseValue (value: any): Object {
+  let path: ?string
+  let locale: ?Locale
+  let args: any
+  let choice: ?number
+
+  if (isString(value)) {
+    path = value
+  } else if (isPlainObject(value)) {
+    path = value.path
+    locale = value.locale
+    args = value.args
+    choice = value.choice
+  }
+
+  return { path, locale, args, choice }
+}
+
+function makeParams (locale: Locale, args: any): Array<any> {
+  const params: Array<any> = []
+
+  locale && params.push(locale)
+  if (args && (Array.isArray(args) || isPlainObject(args))) {
+    params.push(args)
+  }
+
+  return params
+}

+ 33 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/extend.js

@@ -0,0 +1,33 @@
+/* @flow */
+
+export default function extend (Vue: any): void {
+  if (!Vue.prototype.hasOwnProperty('$i18n')) {
+    // $FlowFixMe
+    Object.defineProperty(Vue.prototype, '$i18n', {
+      get () { return this._i18n }
+    })
+  }
+
+  Vue.prototype.$t = function (key: Path, ...values: any): TranslateResult {
+    const i18n = this.$i18n
+    return i18n._t(key, i18n.locale, i18n._getMessages(), this, ...values)
+  }
+
+  Vue.prototype.$tc = function (key: Path, choice?: number, ...values: any): TranslateResult {
+    const i18n = this.$i18n
+    return i18n._tc(key, i18n.locale, i18n._getMessages(), this, choice, ...values)
+  }
+
+  Vue.prototype.$te = function (key: Path, locale?: Locale): boolean {
+    const i18n = this.$i18n
+    return i18n._te(key, i18n.locale, i18n._getMessages(), locale)
+  }
+
+  Vue.prototype.$d = function (value: number | Date, ...args: any): DateTimeFormatResult {
+    return this.$i18n.d(value, ...args)
+  }
+
+  Vue.prototype.$n = function (value: number, ...args: any): NumberFormatResult {
+    return this.$i18n.n(value, ...args)
+  }
+}

+ 114 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/format.js

@@ -0,0 +1,114 @@
+/* @flow */
+
+import { warn, isObject } from './util'
+
+export default class BaseFormatter {
+  _caches: { [key: string]: Array<Token> }
+
+  constructor () {
+    this._caches = Object.create(null)
+  }
+
+  interpolate (message: string, values: any): Array<any> {
+    if (!values) {
+      return [message]
+    }
+    let tokens: Array<Token> = this._caches[message]
+    if (!tokens) {
+      tokens = parse(message)
+      this._caches[message] = tokens
+    }
+    return compile(tokens, values)
+  }
+}
+
+type Token = {
+  type: 'text' | 'named' | 'list' | 'unknown',
+  value: string
+}
+
+const RE_TOKEN_LIST_VALUE: RegExp = /^(?:\d)+/
+const RE_TOKEN_NAMED_VALUE: RegExp = /^(?:\w)+/
+
+export function parse (format: string): Array<Token> {
+  const tokens: Array<Token> = []
+  let position: number = 0
+
+  let text: string = ''
+  while (position < format.length) {
+    let char: string = format[position++]
+    if (char === '{') {
+      if (text) {
+        tokens.push({ type: 'text', value: text })
+      }
+
+      text = ''
+      let sub: string = ''
+      char = format[position++]
+      while (char !== undefined && char !== '}') {
+        sub += char
+        char = format[position++]
+      }
+      const isClosed = char === '}'
+
+      const type = RE_TOKEN_LIST_VALUE.test(sub)
+        ? 'list'
+        : isClosed && RE_TOKEN_NAMED_VALUE.test(sub)
+          ? 'named'
+          : 'unknown'
+      tokens.push({ value: sub, type })
+    } else if (char === '%') {
+      // when found rails i18n syntax, skip text capture
+      if (format[(position)] !== '{') {
+        text += char
+      }
+    } else {
+      text += char
+    }
+  }
+
+  text && tokens.push({ type: 'text', value: text })
+
+  return tokens
+}
+
+export function compile (tokens: Array<Token>, values: Object | Array<any>): Array<any> {
+  const compiled: Array<any> = []
+  let index: number = 0
+
+  const mode: string = Array.isArray(values)
+    ? 'list'
+    : isObject(values)
+      ? 'named'
+      : 'unknown'
+  if (mode === 'unknown') { return compiled }
+
+  while (index < tokens.length) {
+    const token: Token = tokens[index]
+    switch (token.type) {
+      case 'text':
+        compiled.push(token.value)
+        break
+      case 'list':
+        compiled.push(values[parseInt(token.value, 10)])
+        break
+      case 'named':
+        if (mode === 'named') {
+          compiled.push((values: any)[token.value])
+        } else {
+          if (process.env.NODE_ENV !== 'production') {
+            warn(`Type of token '${token.type}' and format of value '${mode}' don't match!`)
+          }
+        }
+        break
+      case 'unknown':
+        if (process.env.NODE_ENV !== 'production') {
+          warn(`Detect 'unknown' type of token!`)
+        }
+        break
+    }
+    index++
+  }
+
+  return compiled
+}

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1120 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/index.js


+ 40 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/install.js

@@ -0,0 +1,40 @@
+import { warn } from './util'
+import extend from './extend'
+import defineMixin from './mixin'
+import interpolationComponent from './components/interpolation'
+import numberComponent from './components/number'
+import { bind, update, unbind } from './directive'
+
+export let Vue
+
+export function install (_Vue, options = { bridge: false }) {
+  /* istanbul ignore if */
+  if (process.env.NODE_ENV !== 'production' && install.installed && _Vue === Vue) {
+    warn('already installed.')
+    return
+  }
+  install.installed = true
+
+  Vue = _Vue
+
+  const version = (Vue.version && Number(Vue.version.split('.')[0])) || -1
+  /* istanbul ignore if */
+  if (process.env.NODE_ENV !== 'production' && version < 2) {
+    warn(`vue-i18n (${install.version}) need to use Vue 2.0 or later (Vue: ${Vue.version}).`)
+    return
+  }
+
+  extend(Vue)
+  Vue.mixin(defineMixin(options.bridge))
+  Vue.directive('t', { bind, update, unbind })
+  Vue.component(interpolationComponent.name, interpolationComponent)
+  Vue.component(numberComponent.name, numberComponent)
+
+  // use simple mergeStrategies to prevent i18n instance lose '__proto__'
+  const strats = Vue.config.optionMergeStrategies
+  strats.i18n = function (parentVal, childVal) {
+    return childVal === undefined
+      ? parentVal
+      : childVal
+  }
+}

+ 159 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/mixin.js

@@ -0,0 +1,159 @@
+/* @flow */
+
+import VueI18n from './index'
+import { isPlainObject, warn, error, merge } from './util'
+
+/**
+ * Mixin
+ * 
+ * If `bridge` mode, empty mixin is returned,
+ * else regulary mixin implementation is returned.
+ */
+export default function defineMixin (bridge: boolean = false) {
+  function mounted (): void {
+    if (this !== this.$root && this.$options.__INTLIFY_META__ && this.$el) {
+      this.$el.setAttribute('data-intlify', this.$options.__INTLIFY_META__)
+    }
+  }
+
+  return bridge
+    ? { mounted } // delegate `vue-i18n-bridge` mixin implementation
+    : { // regulary 
+    beforeCreate (): void {
+      const options: any = this.$options
+      options.i18n = options.i18n || ((options.__i18nBridge || options.__i18n) ? {} : null)
+
+      if (options.i18n) {
+        if (options.i18n instanceof VueI18n) {
+          // init locale messages via custom blocks
+          if ((options.__i18nBridge || options.__i18n)) {
+            try {
+              let localeMessages = options.i18n && options.i18n.messages ? options.i18n.messages : {}
+              const __i18n = options.__i18nBridge || options.__i18n
+              __i18n.forEach(resource => {
+                localeMessages = merge(localeMessages, JSON.parse(resource))
+              })
+              Object.keys(localeMessages).forEach((locale: Locale) => {
+                options.i18n.mergeLocaleMessage(locale, localeMessages[locale])
+              })
+            } catch (e) {
+              if (process.env.NODE_ENV !== 'production') {
+                error(`Cannot parse locale messages via custom blocks.`, e)
+              }
+            }
+          }
+          this._i18n = options.i18n
+          this._i18nWatcher = this._i18n.watchI18nData()
+        } else if (isPlainObject(options.i18n)) {
+          const rootI18n = this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n
+            ? this.$root.$i18n
+            : null
+          // component local i18n
+          if (rootI18n) {
+            options.i18n.root = this.$root
+            options.i18n.formatter = rootI18n.formatter
+            options.i18n.fallbackLocale = rootI18n.fallbackLocale
+            options.i18n.formatFallbackMessages = rootI18n.formatFallbackMessages
+            options.i18n.silentTranslationWarn = rootI18n.silentTranslationWarn
+            options.i18n.silentFallbackWarn = rootI18n.silentFallbackWarn
+            options.i18n.pluralizationRules = rootI18n.pluralizationRules
+            options.i18n.preserveDirectiveContent = rootI18n.preserveDirectiveContent
+          }
+
+          // init locale messages via custom blocks
+          if ((options.__i18nBridge || options.__i18n)) {
+            try {
+              let localeMessages = options.i18n && options.i18n.messages ? options.i18n.messages : {}
+              const __i18n = options.__i18nBridge || options.__i18n
+              __i18n.forEach(resource => {
+                localeMessages = merge(localeMessages, JSON.parse(resource))
+              })
+              options.i18n.messages = localeMessages
+            } catch (e) {
+              if (process.env.NODE_ENV !== 'production') {
+                warn(`Cannot parse locale messages via custom blocks.`, e)
+              }
+            }
+          }
+
+          const { sharedMessages } = options.i18n
+          if (sharedMessages && isPlainObject(sharedMessages)) {
+            options.i18n.messages = merge(options.i18n.messages, sharedMessages)
+          }
+
+          this._i18n = new VueI18n(options.i18n)
+          this._i18nWatcher = this._i18n.watchI18nData()
+
+          if (options.i18n.sync === undefined || !!options.i18n.sync) {
+            this._localeWatcher = this.$i18n.watchLocale()
+          }
+
+          if (rootI18n) {
+            rootI18n.onComponentInstanceCreated(this._i18n)
+          }
+        } else {
+          if (process.env.NODE_ENV !== 'production') {
+            warn(`Cannot be interpreted 'i18n' option.`)
+          }
+        }
+      } else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
+        // root i18n
+        this._i18n = this.$root.$i18n
+      } else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
+        // parent i18n
+        this._i18n = options.parent.$i18n
+      }
+    },
+
+    beforeMount (): void {
+      const options: any = this.$options
+      options.i18n = options.i18n || ((options.__i18nBridge || options.__i18n) ? {} : null)
+
+      if (options.i18n) {
+        if (options.i18n instanceof VueI18n) {
+          // init locale messages via custom blocks
+          this._i18n.subscribeDataChanging(this)
+          this._subscribing = true
+        } else if (isPlainObject(options.i18n)) {
+          this._i18n.subscribeDataChanging(this)
+          this._subscribing = true
+        } else {
+          if (process.env.NODE_ENV !== 'production') {
+            warn(`Cannot be interpreted 'i18n' option.`)
+          }
+        }
+      } else if (this.$root && this.$root.$i18n && this.$root.$i18n instanceof VueI18n) {
+        this._i18n.subscribeDataChanging(this)
+        this._subscribing = true
+      } else if (options.parent && options.parent.$i18n && options.parent.$i18n instanceof VueI18n) {
+        this._i18n.subscribeDataChanging(this)
+        this._subscribing = true
+      }
+    },
+
+    mounted,
+
+    beforeDestroy (): void {
+      if (!this._i18n) { return }
+
+      const self = this
+      this.$nextTick(() => {
+        if (self._subscribing) {
+          self._i18n.unsubscribeDataChanging(self)
+          delete self._subscribing
+        }
+
+        if (self._i18nWatcher) {
+          self._i18nWatcher()
+          self._i18n.destroyVM()
+          delete self._i18nWatcher
+        }
+
+        if (self._localeWatcher) {
+          self._localeWatcher()
+          delete self._localeWatcher
+        }
+      })
+    }
+  }
+}

+ 302 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/path.js

@@ -0,0 +1,302 @@
+/* @flow */
+
+import { isObject } from './util'
+
+/**
+ *  Path parser
+ *  - Inspired:
+ *    Vue.js Path parser
+ */
+
+// actions
+const APPEND = 0
+const PUSH = 1
+const INC_SUB_PATH_DEPTH = 2
+const PUSH_SUB_PATH = 3
+
+// states
+const BEFORE_PATH = 0
+const IN_PATH = 1
+const BEFORE_IDENT = 2
+const IN_IDENT = 3
+const IN_SUB_PATH = 4
+const IN_SINGLE_QUOTE = 5
+const IN_DOUBLE_QUOTE = 6
+const AFTER_PATH = 7
+const ERROR = 8
+
+const pathStateMachine: any = []
+
+pathStateMachine[BEFORE_PATH] = {
+  'ws': [BEFORE_PATH],
+  'ident': [IN_IDENT, APPEND],
+  '[': [IN_SUB_PATH],
+  'eof': [AFTER_PATH]
+}
+
+pathStateMachine[IN_PATH] = {
+  'ws': [IN_PATH],
+  '.': [BEFORE_IDENT],
+  '[': [IN_SUB_PATH],
+  'eof': [AFTER_PATH]
+}
+
+pathStateMachine[BEFORE_IDENT] = {
+  'ws': [BEFORE_IDENT],
+  'ident': [IN_IDENT, APPEND],
+  '0': [IN_IDENT, APPEND],
+  'number': [IN_IDENT, APPEND]
+}
+
+pathStateMachine[IN_IDENT] = {
+  'ident': [IN_IDENT, APPEND],
+  '0': [IN_IDENT, APPEND],
+  'number': [IN_IDENT, APPEND],
+  'ws': [IN_PATH, PUSH],
+  '.': [BEFORE_IDENT, PUSH],
+  '[': [IN_SUB_PATH, PUSH],
+  'eof': [AFTER_PATH, PUSH]
+}
+
+pathStateMachine[IN_SUB_PATH] = {
+  "'": [IN_SINGLE_QUOTE, APPEND],
+  '"': [IN_DOUBLE_QUOTE, APPEND],
+  '[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH],
+  ']': [IN_PATH, PUSH_SUB_PATH],
+  'eof': ERROR,
+  'else': [IN_SUB_PATH, APPEND]
+}
+
+pathStateMachine[IN_SINGLE_QUOTE] = {
+  "'": [IN_SUB_PATH, APPEND],
+  'eof': ERROR,
+  'else': [IN_SINGLE_QUOTE, APPEND]
+}
+
+pathStateMachine[IN_DOUBLE_QUOTE] = {
+  '"': [IN_SUB_PATH, APPEND],
+  'eof': ERROR,
+  'else': [IN_DOUBLE_QUOTE, APPEND]
+}
+
+/**
+ * Check if an expression is a literal value.
+ */
+
+const literalValueRE: RegExp = /^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/
+function isLiteral (exp: string): boolean {
+  return literalValueRE.test(exp)
+}
+
+/**
+ * Strip quotes from a string
+ */
+
+function stripQuotes (str: string): string | boolean {
+  const a: number = str.charCodeAt(0)
+  const b: number = str.charCodeAt(str.length - 1)
+  return a === b && (a === 0x22 || a === 0x27)
+    ? str.slice(1, -1)
+    : str
+}
+
+/**
+ * Determine the type of a character in a keypath.
+ */
+
+function getPathCharType (ch: ?string): string {
+  if (ch === undefined || ch === null) { return 'eof' }
+
+  const code: number = ch.charCodeAt(0)
+
+  switch (code) {
+    case 0x5B: // [
+    case 0x5D: // ]
+    case 0x2E: // .
+    case 0x22: // "
+    case 0x27: // '
+      return ch
+
+    case 0x5F: // _
+    case 0x24: // $
+    case 0x2D: // -
+      return 'ident'
+
+    case 0x09: // Tab
+    case 0x0A: // Newline
+    case 0x0D: // Return
+    case 0xA0:  // No-break space
+    case 0xFEFF:  // Byte Order Mark
+    case 0x2028:  // Line Separator
+    case 0x2029:  // Paragraph Separator
+      return 'ws'
+  }
+
+  return 'ident'
+}
+
+/**
+ * Format a subPath, return its plain form if it is
+ * a literal string or number. Otherwise prepend the
+ * dynamic indicator (*).
+ */
+
+function formatSubPath (path: string): boolean | string {
+  const trimmed: string = path.trim()
+  // invalid leading 0
+  if (path.charAt(0) === '0' && isNaN(path)) { return false }
+
+  return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed
+}
+
+/**
+ * Parse a string path into an array of segments
+ */
+
+function parse (path: Path): ?Array<string> {
+  const keys: Array<string> = []
+  let index: number = -1
+  let mode: number = BEFORE_PATH
+  let subPathDepth: number = 0
+  let c: ?string
+  let key: any
+  let newChar: any
+  let type: string
+  let transition: number
+  let action: Function
+  let typeMap: any
+  const actions: Array<Function> = []
+
+  actions[PUSH] = function () {
+    if (key !== undefined) {
+      keys.push(key)
+      key = undefined
+    }
+  }
+
+  actions[APPEND] = function () {
+    if (key === undefined) {
+      key = newChar
+    } else {
+      key += newChar
+    }
+  }
+
+  actions[INC_SUB_PATH_DEPTH] = function () {
+    actions[APPEND]()
+    subPathDepth++
+  }
+
+  actions[PUSH_SUB_PATH] = function () {
+    if (subPathDepth > 0) {
+      subPathDepth--
+      mode = IN_SUB_PATH
+      actions[APPEND]()
+    } else {
+      subPathDepth = 0
+      if (key === undefined) { return false }
+      key = formatSubPath(key)
+      if (key === false) {
+        return false
+      } else {
+        actions[PUSH]()
+      }
+    }
+  }
+
+  function maybeUnescapeQuote (): ?boolean {
+    const nextChar: string = path[index + 1]
+    if ((mode === IN_SINGLE_QUOTE && nextChar === "'") ||
+      (mode === IN_DOUBLE_QUOTE && nextChar === '"')) {
+      index++
+      newChar = '\\' + nextChar
+      actions[APPEND]()
+      return true
+    }
+  }
+
+  while (mode !== null) {
+    index++
+    c = path[index]
+
+    if (c === '\\' && maybeUnescapeQuote()) {
+      continue
+    }
+
+    type = getPathCharType(c)
+    typeMap = pathStateMachine[mode]
+    transition = typeMap[type] || typeMap['else'] || ERROR
+
+    if (transition === ERROR) {
+      return // parse error
+    }
+
+    mode = transition[0]
+    action = actions[transition[1]]
+    if (action) {
+      newChar = transition[2]
+      newChar = newChar === undefined
+        ? c
+        : newChar
+      if (action() === false) {
+        return
+      }
+    }
+
+    if (mode === AFTER_PATH) {
+      return keys
+    }
+  }
+}
+
+export type PathValue = PathValueObject | PathValueArray | Function | string | number | boolean | null
+export type PathValueObject = { [key: string]: PathValue }
+export type PathValueArray = Array<PathValue>
+
+export default class I18nPath {
+  _cache: Object
+
+  constructor () {
+    this._cache = Object.create(null)
+  }
+
+  /**
+   * External parse that check for a cache hit first
+   */
+  parsePath (path: Path): Array<string> {
+    let hit: ?Array<string> = this._cache[path]
+    if (!hit) {
+      hit = parse(path)
+      if (hit) {
+        this._cache[path] = hit
+      }
+    }
+    return hit || []
+  }
+
+  /**
+   * Get path value from path string
+   */
+  getPathValue (obj: mixed, path: Path): PathValue {
+    if (!isObject(obj)) { return null }
+
+    const paths: Array<string> = this.parsePath(path)
+    if (paths.length === 0) {
+      return null
+    } else {
+      const length: number = paths.length
+      let last: any = obj
+      let i: number = 0
+      while (i < length) {
+        const value: any = last[paths[i]]
+        if (value === undefined || value === null) {
+          return null
+        }
+        last = value
+        i++
+      }
+
+      return last
+    }
+  }
+}

+ 209 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/src/util.js

@@ -0,0 +1,209 @@
+/* @flow */
+
+/**
+ * constants
+ */
+
+export const numberFormatKeys = [
+  'compactDisplay',
+  'currency',
+  'currencyDisplay',
+  'currencySign',
+  'localeMatcher',
+  'notation',
+  'numberingSystem',
+  'signDisplay',
+  'style',
+  'unit',
+  'unitDisplay',
+  'useGrouping',
+  'minimumIntegerDigits',
+  'minimumFractionDigits',
+  'maximumFractionDigits',
+  'minimumSignificantDigits',
+  'maximumSignificantDigits'
+]
+
+/**
+ * utilities
+ */
+
+export function warn (msg: string, err: ?Error): void {
+  if (typeof console !== 'undefined') {
+    console.warn('[vue-i18n] ' + msg)
+    /* istanbul ignore if */
+    if (err) {
+      console.warn(err.stack)
+    }
+  }
+}
+
+export function error (msg: string, err: ?Error): void {
+  if (typeof console !== 'undefined') {
+    console.error('[vue-i18n] ' + msg)
+    /* istanbul ignore if */
+    if (err) {
+      console.error(err.stack)
+    }
+  }
+}
+
+export const isArray = Array.isArray
+
+export function isObject (obj: mixed): boolean %checks {
+  return obj !== null && typeof obj === 'object'
+}
+
+export function isBoolean (val: mixed): boolean %checks {
+  return typeof val === 'boolean'
+}
+
+export function isString (val: mixed): boolean %checks {
+  return typeof val === 'string'
+}
+
+const toString: Function = Object.prototype.toString
+const OBJECT_STRING: string = '[object Object]'
+export function isPlainObject (obj: any): boolean {
+  return toString.call(obj) === OBJECT_STRING
+}
+
+export function isNull (val: mixed): boolean {
+  return val === null || val === undefined
+}
+
+export function isFunction (val: mixed): boolean %checks {
+  return typeof val === 'function'
+}
+
+export function parseArgs (...args: Array<mixed>): Object {
+  let locale: ?string = null
+  let params: mixed = null
+  if (args.length === 1) {
+    if (isObject(args[0]) || isArray(args[0])) {
+      params = args[0]
+    } else if (typeof args[0] === 'string') {
+      locale = args[0]
+    }
+  } else if (args.length === 2) {
+    if (typeof args[0] === 'string') {
+      locale = args[0]
+    }
+    /* istanbul ignore if */
+    if (isObject(args[1]) || isArray(args[1])) {
+      params = args[1]
+    }
+  }
+
+  return { locale, params }
+}
+
+export function looseClone (obj: Object): Object {
+  return JSON.parse(JSON.stringify(obj))
+}
+
+export function remove (arr: Set<any>, item: any): Set<any> | void {
+  if (arr.delete(item)) {
+    return arr
+  }
+}
+
+export function arrayFrom (arr: Set<any>): Array<any> {
+  const ret = []
+  arr.forEach(a => ret.push(a))
+  return ret
+}
+
+export function includes (arr: Array<any>, item: any): boolean {
+  return !!~arr.indexOf(item)
+}
+
+const hasOwnProperty = Object.prototype.hasOwnProperty
+export function hasOwn (obj: Object | Array<*>, key: string): boolean {
+  return hasOwnProperty.call(obj, key)
+}
+
+export function merge (target: Object): Object {
+  const output = Object(target)
+  for (let i = 1; i < arguments.length; i++) {
+    const source = arguments[i]
+    if (source !== undefined && source !== null) {
+      let key
+      for (key in source) {
+        if (hasOwn(source, key)) {
+          if (isObject(source[key])) {
+            output[key] = merge(output[key], source[key])
+          } else {
+            output[key] = source[key]
+          }
+        }
+      }
+    }
+  }
+  return output
+}
+
+export function looseEqual (a: any, b: any): boolean {
+  if (a === b) { return true }
+  const isObjectA: boolean = isObject(a)
+  const isObjectB: boolean = isObject(b)
+  if (isObjectA && isObjectB) {
+    try {
+      const isArrayA: boolean = isArray(a)
+      const isArrayB: boolean = isArray(b)
+      if (isArrayA && isArrayB) {
+        return a.length === b.length && a.every((e: any, i: number): boolean => {
+          return looseEqual(e, b[i])
+        })
+      } else if (!isArrayA && !isArrayB) {
+        const keysA: Array<string> = Object.keys(a)
+        const keysB: Array<string> = Object.keys(b)
+        return keysA.length === keysB.length && keysA.every((key: string): boolean => {
+          return looseEqual(a[key], b[key])
+        })
+      } else {
+        /* istanbul ignore next */
+        return false
+      }
+    } catch (e) {
+      /* istanbul ignore next */
+      return false
+    }
+  } else if (!isObjectA && !isObjectB) {
+    return String(a) === String(b)
+  } else {
+    return false
+  }
+}
+
+/**
+ * Sanitizes html special characters from input strings. For mitigating risk of XSS attacks.
+ * @param rawText The raw input from the user that should be escaped.
+ */
+function escapeHtml(rawText: string): string {
+  return rawText
+    .replace(/</g, '&lt;')
+    .replace(/>/g, '&gt;')
+    .replace(/"/g, '&quot;')
+    .replace(/'/g, '&apos;')
+}
+
+/**
+ * Escapes html tags and special symbols from all provided params which were returned from parseArgs().params.
+ * This method performs an in-place operation on the params object.
+ *
+ * @param {any} params Parameters as provided from `parseArgs().params`.
+ *                     May be either an array of strings or a string->any map.
+ *
+ * @returns The manipulated `params` object.
+ */
+export function escapeParams(params: any): any {
+  if(params != null) {
+    Object.keys(params).forEach(key => {
+      if(typeof(params[key]) == 'string') {
+        params[key] = escapeHtml(params[key])
+      }
+    })
+  }
+  return params
+}

+ 295 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/types/index.d.ts

@@ -0,0 +1,295 @@
+export type Path = VueI18n.Path;
+export type Locale = VueI18n.Locale;
+export type FallbackLocale = VueI18n.FallbackLocale;
+export type Values = VueI18n.Values;
+export type Choice = VueI18n.Choice;
+export type MessageContext = VueI18n.MessageContext;
+export type MessageFunction = VueI18n.MessageFunction;
+export type LocaleMessage = VueI18n.LocaleMessage;
+export type LocaleMessageObject = VueI18n.LocaleMessageObject;
+export type LocaleMessageArray = VueI18n.LocaleMessageArray;
+export type LocaleMessages = VueI18n.LocaleMessages;
+export type TranslateResult = VueI18n.TranslateResult;
+export type DateTimeFormatOptions = VueI18n.DateTimeFormatOptions;
+export type DateTimeFormat = VueI18n.DateTimeFormat;
+export type DateTimeFormats = VueI18n.DateTimeFormats;
+export type DateTimeFormatResult = VueI18n.DateTimeFormatResult;
+export type NumberFormatOptions = VueI18n.NumberFormatOptions;
+export type NumberFormat = VueI18n.NumberFormat;
+export type NumberFormats = VueI18n.NumberFormats;
+export type NumberFormatResult = VueI18n.NumberFormatResult;
+export type NumberFormatToPartsResult = VueI18n.NumberFormatToPartsResult;
+export type WarnHtmlInMessageLevel = VueI18n.WarnHtmlInMessageLevel;
+export type Formatter = VueI18n.Formatter;
+export type MissingHandler = VueI18n.MissingHandler;
+export type PostTranslationHandler = VueI18n.PostTranslationHandler;
+export type IntlAvailability = VueI18n.IntlAvailability;
+export type I18nOptions = VueI18n.I18nOptions;
+export type PluignOptions = VueI18n.PluignOptions
+
+import Vue, { PluginFunction } from 'vue';
+
+declare namespace VueI18n {
+  type Path = string;
+  type Locale = string;
+  type FallbackLocale = string | string[] | false | { [locale: string]: string[] }
+  type Values = any[] | { [key: string]: any };
+  type Choice = number;
+  interface MessageContext {
+    list(index: number): unknown
+    named(key: string): unknown
+    linked(key: string): VueI18n.TranslateResult
+    values: any
+    path: string
+    formatter: Formatter
+    messages: LocaleMessages
+    locale: Locale
+  }
+  type MessageFunction = (ctx: MessageContext) => string;
+  type LocaleMessage = string | MessageFunction | LocaleMessageObject | LocaleMessageArray;
+  interface LocaleMessageObject { [key: string]: LocaleMessage; }
+  interface LocaleMessageArray { [index: number]: LocaleMessage; }
+  interface LocaleMessages { [key: string]: LocaleMessageObject; }
+  type TranslateResult = string | LocaleMessages;
+
+  type LocaleMatcher = 'lookup' | 'best fit';
+  type FormatMatcher = 'basic' | 'best fit';
+
+  type DateTimeHumanReadable = 'long' | 'short' | 'narrow';
+  type DateTimeDigital = 'numeric' | '2-digit';
+
+  interface SpecificDateTimeFormatOptions extends Intl.DateTimeFormatOptions {
+    year?: DateTimeDigital;
+    month?: DateTimeDigital | DateTimeHumanReadable;
+    day?: DateTimeDigital;
+    hour?: DateTimeDigital;
+    minute?: DateTimeDigital;
+    second?: DateTimeDigital;
+    weekday?: DateTimeHumanReadable;
+    era?: DateTimeHumanReadable;
+    timeZoneName?: 'long' | 'short';
+    localeMatcher?: LocaleMatcher;
+    formatMatcher?: FormatMatcher;
+  }
+
+  type DateTimeFormatOptions = Intl.DateTimeFormatOptions | SpecificDateTimeFormatOptions;
+
+  interface DateTimeFormat { [key: string]: DateTimeFormatOptions; }
+  interface DateTimeFormats { [locale: string]: DateTimeFormat; }
+  type DateTimeFormatResult = string;
+
+  type CurrencyDisplay = 'symbol' | 'code' | 'name';
+
+  interface SpecificNumberFormatOptions extends Intl.NumberFormatOptions {
+    style?: 'decimal' | 'percent';
+    currency?: string;
+    currencyDisplay?: CurrencyDisplay;
+    localeMatcher?: LocaleMatcher;
+    formatMatcher?: FormatMatcher;
+  }
+
+  interface CurrencyNumberFormatOptions extends Intl.NumberFormatOptions {
+    style: 'currency';
+    currency: string; // Obligatory if style is 'currency'
+    currencyDisplay?: CurrencyDisplay;
+    localeMatcher?: LocaleMatcher;
+    formatMatcher?: FormatMatcher;
+  }
+
+  type NumberFormatOptions = Intl.NumberFormatOptions | SpecificNumberFormatOptions | CurrencyNumberFormatOptions;
+
+  interface NumberFormat { [key: string]: NumberFormatOptions; }
+  interface NumberFormats { [locale: string]: NumberFormat; }
+  type NumberFormatResult = string;
+  type PluralizationRulesMap = {
+    /**
+     * @param choice {number} a choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
+     * @param choicesLength {number} an overall amount of available choices
+     * @returns a final choice index
+    */
+    [lang: string]: (choice: number, choicesLength: number) => number;
+  };
+  type Modifiers = { [key: string]: (str : string) => string };
+
+  type FormattedNumberPartType = 'currency' | 'decimal' | 'fraction' | 'group' | 'infinity' | 'integer' | 'literal' | 'minusSign' | 'nan' | 'plusSign' | 'percentSign';
+
+  type WarnHtmlInMessageLevel = 'off' | 'warn' | 'error';
+
+  interface FormattedNumberPart {
+    type: FormattedNumberPartType;
+    value: string;
+  }
+  interface NumberFormatToPartsResult { [index: number]: FormattedNumberPart; }
+
+  interface Formatter {
+    interpolate(message: string, values: Values | undefined, path: string): (any[] | null);
+  }
+
+  type MissingHandler = (locale: Locale, key: Path, vm: Vue | null, values: any) => string | void;
+  type PostTranslationHandler = (str: string, key?: string) => string;
+  type ComponentInstanceCreatedListener = (newVm: VueI18n & IVueI18n, rootVm: VueI18n & IVueI18n) => void;
+
+  interface IntlAvailability {
+    dateTimeFormat: boolean;
+    numberFormat: boolean;
+  }
+
+  // tslint:disable-next-line:interface-name
+  interface I18nOptions {
+    locale?: Locale;
+    fallbackLocale?: FallbackLocale;
+    messages?: LocaleMessages;
+    dateTimeFormats?: DateTimeFormats;
+    numberFormats?: NumberFormats;
+    formatter?: Formatter;
+    modifiers?: Modifiers,
+    missing?: MissingHandler;
+    fallbackRoot?: boolean;
+    fallbackRootWithEmptyString?: boolean,
+    formatFallbackMessages?: boolean;
+    sync?: boolean;
+    silentTranslationWarn?: boolean | RegExp;
+    silentFallbackWarn?: boolean | RegExp;
+    preserveDirectiveContent?: boolean;
+    pluralizationRules?: PluralizationRulesMap;
+    warnHtmlInMessage?: WarnHtmlInMessageLevel;
+    sharedMessages?: LocaleMessages;
+    postTranslation?: PostTranslationHandler;
+    componentInstanceCreatedListener?: ComponentInstanceCreatedListener;
+    escapeParameterHtml?: boolean;
+  }
+
+  type PluignOptions = {
+    bridge?: boolean
+  }
+}
+
+export declare interface IVueI18n {
+  readonly messages: VueI18n.LocaleMessages;
+  readonly dateTimeFormats: VueI18n.DateTimeFormats;
+  readonly numberFormats: VueI18n.NumberFormats;
+
+  locale: VueI18n.Locale;
+  fallbackLocale: VueI18n.FallbackLocale;
+  missing: VueI18n.MissingHandler;
+  formatter: VueI18n.Formatter;
+  formatFallbackMessages: boolean;
+  silentTranslationWarn: boolean | RegExp;
+  silentFallbackWarn: boolean | RegExp;
+  preserveDirectiveContent: boolean;
+  sync: boolean;
+  pluralizationRules: VueI18n.PluralizationRulesMap;
+  warnHtmlInMessage: VueI18n.WarnHtmlInMessageLevel;
+  postTranslation: VueI18n.PostTranslationHandler;
+  t(key: VueI18n.Path, values?: VueI18n.Values): VueI18n.TranslateResult;
+  t(key: VueI18n.Path, locale: VueI18n.Locale, values?: VueI18n.Values): VueI18n.TranslateResult;
+  tc(key: VueI18n.Path, choice?: VueI18n.Choice, values?: VueI18n.Values): string;
+  tc(
+    key: VueI18n.Path,
+    choice: VueI18n.Choice,
+    locale: VueI18n.Locale,
+    values?: VueI18n.Values,
+  ): string;
+  te(key: VueI18n.Path, locale?: VueI18n.Locale): boolean;
+  d(
+    value: number | Date,
+    key?: VueI18n.Path,
+    locale?: VueI18n.Locale,
+  ): VueI18n.DateTimeFormatResult;
+  d(value: number | Date, args?: { [key: string]: string }): VueI18n.DateTimeFormatResult;
+  d(value: number | Date, options?: VueI18n.DateTimeFormatOptions): VueI18n.DateTimeFormatResult;
+  n(value: number, key?: VueI18n.Path, locale?: VueI18n.Locale): VueI18n.NumberFormatResult;
+  n(value: number, args?: { [key: string]: string }): VueI18n.NumberFormatResult;
+  n(value: number, options?: VueI18n.NumberFormatOptions, locale?: VueI18n.Locale): VueI18n.NumberFormatResult;
+  getLocaleMessage(locale: VueI18n.Locale): VueI18n.LocaleMessageObject;
+  setLocaleMessage(locale: VueI18n.Locale, message: VueI18n.LocaleMessageObject): void;
+  mergeLocaleMessage(locale: VueI18n.Locale, message: VueI18n.LocaleMessageObject): void;
+  getDateTimeFormat(locale: VueI18n.Locale): VueI18n.DateTimeFormat;
+  setDateTimeFormat(locale: VueI18n.Locale, format: VueI18n.DateTimeFormat): void;
+  mergeDateTimeFormat(locale: VueI18n.Locale, format: VueI18n.DateTimeFormat): void;
+  getNumberFormat(locale: VueI18n.Locale): VueI18n.NumberFormat;
+  setNumberFormat(locale: VueI18n.Locale, format: VueI18n.NumberFormat): void;
+  mergeNumberFormat(locale: VueI18n.Locale, format: VueI18n.NumberFormat): void;
+  getChoiceIndex: (choice: number, choicesLength: number) => number;
+}
+
+declare class VueI18n {
+  constructor(options?: VueI18n.I18nOptions)
+
+  readonly messages: VueI18n.LocaleMessages;
+  readonly dateTimeFormats: VueI18n.DateTimeFormats;
+  readonly numberFormats: VueI18n.NumberFormats;
+  readonly availableLocales: VueI18n.Locale[];
+
+  locale: VueI18n.Locale;
+  fallbackLocale: VueI18n.FallbackLocale;
+  missing: VueI18n.MissingHandler;
+  formatter: VueI18n.Formatter;
+  formatFallbackMessages: boolean;
+  silentTranslationWarn: boolean | RegExp;
+  silentFallbackWarn: boolean | RegExp;
+  preserveDirectiveContent: boolean;
+  pluralizationRules: VueI18n.PluralizationRulesMap;
+  warnHtmlInMessage: VueI18n.WarnHtmlInMessageLevel;
+  postTranslation: VueI18n.PostTranslationHandler;
+  sync: boolean;
+
+  t(key: VueI18n.Path, values?: VueI18n.Values): VueI18n.TranslateResult;
+  t(key: VueI18n.Path, locale: VueI18n.Locale, values?: VueI18n.Values): VueI18n.TranslateResult;
+  tc(key: VueI18n.Path, choice?: VueI18n.Choice, values?: VueI18n.Values): string;
+  tc(key: VueI18n.Path, choice: VueI18n.Choice, locale: VueI18n.Locale, values?: VueI18n.Values): string;
+  te(key: VueI18n.Path, locale?: VueI18n.Locale): boolean;
+  d(value: number | Date, key?: VueI18n.Path, locale?: VueI18n.Locale): VueI18n.DateTimeFormatResult;
+  d(value: number | Date, args?: { [key: string]: string }): VueI18n.DateTimeFormatResult;
+  d(value: number | Date, options?: VueI18n.DateTimeFormatOptions): VueI18n.DateTimeFormatResult;
+  n(value: number, key?: VueI18n.Path, locale?: VueI18n.Locale): VueI18n.NumberFormatResult;
+  n(value: number, args?: { [key: string]: string }): VueI18n.NumberFormatResult;
+  n(value: number, options?: VueI18n.NumberFormatOptions, locale?: VueI18n.Locale): VueI18n.NumberFormatResult;
+
+  getLocaleMessage(locale: VueI18n.Locale): VueI18n.LocaleMessageObject;
+  setLocaleMessage(locale: VueI18n.Locale, message: VueI18n.LocaleMessageObject): void;
+  mergeLocaleMessage(locale: VueI18n.Locale, message: VueI18n.LocaleMessageObject): void;
+
+  getDateTimeFormat(locale: VueI18n.Locale): VueI18n.DateTimeFormat;
+  setDateTimeFormat(locale: VueI18n.Locale, format: VueI18n.DateTimeFormat): void;
+  mergeDateTimeFormat(locale: VueI18n.Locale, format: VueI18n.DateTimeFormat): void;
+
+  getNumberFormat(locale: VueI18n.Locale): VueI18n.NumberFormat;
+  setNumberFormat(locale: VueI18n.Locale, format: VueI18n.NumberFormat): void;
+  mergeNumberFormat(locale: VueI18n.Locale, format: VueI18n.NumberFormat): void;
+
+  /**
+   * @param choice {number} a choice index given by the input to $tc: `$tc('path.to.rule', choiceIndex)`
+   * @param choicesLength {number} an overall amount of available choices
+   * @returns a final choice index
+  */
+  getChoiceIndex: (choice: number, choicesLength: number) => number;
+
+  static install: PluginFunction<VueI18n.PluignOptions>;
+  static version: string;
+  static availabilities: VueI18n.IntlAvailability;
+}
+
+declare module 'vue/types/vue' {
+  interface Vue {
+    readonly $i18n: VueI18n & IVueI18n;
+    $t: typeof VueI18n.prototype.t;
+    $tc: typeof VueI18n.prototype.tc;
+    $te: typeof VueI18n.prototype.te;
+    $d: typeof VueI18n.prototype.d;
+    $n: typeof VueI18n.prototype.n;
+  }
+}
+
+declare module 'vue/types/options' {
+  interface ComponentOptions<V extends Vue> {
+    i18n?: {
+      messages?: VueI18n.LocaleMessages;
+      dateTimeFormats?: VueI18n.DateTimeFormats;
+      numberFormats?: VueI18n.NumberFormats;
+      sharedMessages?: VueI18n.LocaleMessages;
+    };
+  }
+}
+
+export default VueI18n;

+ 34 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/vetur/attributes.json

@@ -0,0 +1,34 @@
+{
+  "i18n/path" : {
+    "description": "[required]\nKeypath of the locale message",
+    "type": "string"
+  },
+  "i18n/locale" : {
+    "description": "[optional]\nLocale to be used in this translation",
+    "type": "string"
+  },
+  "i18n/tag" : {
+    "description": "[optional]\nWhich tag to render, default is \"span\"",
+    "type": "string"
+  },
+  "i18n/places": {
+    "description": "[optional after v8.14]\nWill be removed in the next major version, use the slot syntax instead\n\nhttp://kazupon.github.io/vue-i18n/guide/interpolation.html#slots-syntax-usage",
+    "type": "array|object"
+  },
+  "i18n-n/value" : {
+    "description": "[required]\nNumber to be used in formatting",
+    "type": "number"
+  },
+  "i18n-n/format": {
+    "description": "[optional]\nNumber format name or object with explicit format options",
+    "type": "string|object"
+  },
+  "i18n-n/locale" : {
+    "description": "[optional]\nLocale to be used in this translation",
+    "type": "string"
+  },
+  "i18n-n/tag" : {
+    "description": "[optional]\nWhich tag to render, default is `span`",
+    "type": "string"
+  }
+}

+ 20 - 0
fhKeeper/formulahousekeeper/node_modules/vue-i18n/vetur/tags.json

@@ -0,0 +1,20 @@
+{
+  "i18n": {
+    "attributes": [
+      "path",
+      "locale",
+      "tag",
+      "places"
+    ],
+    "description": "This is a functional component that can be used when HTML interpolation is needed.\n\nhttp://kazupon.github.io/vue-i18n/guide/interpolation.html#basic-usage"
+  },
+  "i18n-n": {
+    "attributes": [
+      "value",
+      "format",
+      "locale",
+      "tag"
+    ],
+    "description": "This functional component provides a way to use HTML interpolation in pair with number formatting.\n\nhttp://kazupon.github.io/vue-i18n/guide/number.html#custom-formatting"
+  }
+}

+ 11 - 0
fhKeeper/formulahousekeeper/package-lock.json

@@ -0,0 +1,11 @@
+{
+  "requires": true,
+  "lockfileVersion": 1,
+  "dependencies": {
+    "vue-i18n": {
+      "version": "8.27.2",
+      "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.27.2.tgz",
+      "integrity": "sha512-QVzn7u2WVH8F7eSKIM00lujC7x1mnuGPaTnDTmB01Hd709jDtB9kYtBqM+MWmp5AJRx3gnqAdZbee9MelqwFBg=="
+    }
+  }
+}

+ 13 - 11
fhKeeper/formulahousekeeper/timesheet/config/index.js

@@ -1,18 +1,20 @@
 var path = require('path')
 
 //  var ip = '127.0.0.1'
-// var ip = '47.101.180.183'
-// var ip = '192.168.2.7'
+// var ip = '47.101.180.183' 
+// var ip = '192.168.10.6'
+// var ip = '192.168.2.39'
+var ip = '47.100.37.243'
 
-var os = require('os'), ip = '', ifaces = os.networkInterfaces() // 获取本机ip
-for (var i in ifaces) {
-    for (var j in ifaces[i]) {
-        var val = ifaces[i][j]
-        if (val.family === 'IPv4' && val.address !== '127.0.0.1') {
-            ip = val.address
-        }
-    }
-}
+// var os = require('os'), ip = '', ifaces = os.networkInterfaces() // 获取本机ip
+// for (var i in ifaces) {
+//     for (var j in ifaces[i]) {
+//         var val = ifaces[i][j]
+//         if (val.family === 'IPv4' && val.address !== '127.0.0.1') {
+//             ip = val.address
+//         }
+//     }
+// }
 
 module.exports = {
   build: {

+ 11 - 6
fhKeeper/formulahousekeeper/timesheet/package-lock.json

@@ -2815,7 +2815,7 @@
     },
     "el-table-infinite-scroll": {
       "version": "2.0.0",
-      "resolved": "https://registry.npmmirror.com/el-table-infinite-scroll/-/el-table-infinite-scroll-2.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/el-table-infinite-scroll/-/el-table-infinite-scroll-2.0.0.tgz",
       "integrity": "sha512-zDmsGvce4V0wx7j4CBdYi2wgMsv66SbQBp7984gk25Jc8b2nKdjBYrXpFLfMDZ0iYjTDpxkH9+5iEhCgM3+byw==",
       "requires": {
         "core-js": "^3.x",
@@ -2825,7 +2825,7 @@
       "dependencies": {
         "core-js": {
           "version": "3.22.5",
-          "resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.22.5.tgz",
+          "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.5.tgz",
           "integrity": "sha512-VP/xYuvJ0MJWRAobcmQ8F2H6Bsn+s7zqAAjFaHGBMc5AQm7zaelhD1LGduFn2EehEcQcU+br6t+fwbpQ5d1ZWA=="
         }
       }
@@ -5098,7 +5098,7 @@
       "dependencies": {
         "semver": {
           "version": "5.3.0",
-          "resolved": "https://registry.npm.taobao.org/semver/download/semver-5.3.0.tgz?cache=0&sync_timestamp=1616463603361&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-5.3.0.tgz",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
           "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
           "dev": true
         }
@@ -5218,7 +5218,7 @@
     },
     "normalize-wheel": {
       "version": "1.0.1",
-      "resolved": "https://registry.nlark.com/normalize-wheel/download/normalize-wheel-1.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/normalize-wheel/-/normalize-wheel-1.0.1.tgz",
       "integrity": "sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU="
     },
     "npmlog": {
@@ -5235,7 +5235,7 @@
     },
     "nprogress": {
       "version": "0.2.0",
-      "resolved": "https://registry.npm.taobao.org/nprogress/download/nprogress-0.2.0.tgz",
+      "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
       "integrity": "sha1-y480xTIT2JVyP8urkH6UIq28r7E="
     },
     "nth-check": {
@@ -8222,6 +8222,11 @@
       "integrity": "sha512-BXq3jwIagosjgNVae6tkHzzIk6a8MHFtzAdwhnV5VlvPTFxDCvIttgSiHWjdGoTJvXtmRu5HacExfdarRcFhog==",
       "dev": true
     },
+    "vue-i18n": {
+      "version": "8.27.2",
+      "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.27.2.tgz",
+      "integrity": "sha512-QVzn7u2WVH8F7eSKIM00lujC7x1mnuGPaTnDTmB01Hd709jDtB9kYtBqM+MWmp5AJRx3gnqAdZbee9MelqwFBg=="
+    },
     "vue-loader": {
       "version": "11.3.4",
       "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-11.3.4.tgz",
@@ -9343,7 +9348,7 @@
         },
         "path-exists": {
           "version": "3.0.0",
-          "resolved": "https://registry.npm.taobao.org/path-exists/download/path-exists-3.0.0.tgz",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
           "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
           "dev": true
         },

+ 1 - 0
fhKeeper/formulahousekeeper/timesheet/package.json

@@ -26,6 +26,7 @@
     "v-viewer": "^1.6.4",
     "vue": "^2.6.10",
     "vue-clipboard2": "^0.3.0",
+    "vue-i18n": "^8.27.2",
     "vue-pdf": "^4.2.0",
     "vue-quill-editor": "^3.0.6",
     "vue-router": "^2.3.0",

+ 18 - 0
fhKeeper/formulahousekeeper/timesheet/src/i18n/en.js

@@ -0,0 +1,18 @@
+import enLocale from 'element-ui/lib/locale/lang/en'
+export default {
+  "lang": "English",
+  // 导航
+  navigation: {
+    reports: 'hours report', // 工时报告
+    projectManagement: 'project management', // 项目管理
+    professionalAudit: 'Professional audit', // 专业审核
+    departmentAudit: 'Department audit', // 部门审核
+    projectReportReview: 'Project report review', // 项目报告审核
+    ImportDailyReview: 'Import daily review', // 导入日报审核
+    laborCostStatistics: 'Labor cost statistics', // 工时成本统计
+    customizeNumericalStatistics: 'Customize numerical statistics', // 自定义数值统计
+    financialAccountingCost: 'Financial accounting cost', // 财务核算成本
+
+  },
+  ...enLocale
+}

+ 20 - 0
fhKeeper/formulahousekeeper/timesheet/src/i18n/index.js

@@ -0,0 +1,20 @@
+import Vue from 'vue'
+import VueI18n from 'vue-i18n'
+import locale from 'element-ui/lib/locale'
+import zh from './zh'
+import en from './en'
+Vue.use(VueI18n)
+const messages = {
+  en: {
+    ...en,
+  },
+  zh: {
+    ...zh,
+  }
+};
+const i18n = new VueI18n({
+  locale: localStorage.lang || 'zh',
+  messages,
+});
+locale.i18n((key, value) => i18n.t(key, value))
+export default i18n;

+ 9 - 0
fhKeeper/formulahousekeeper/timesheet/src/i18n/zh.js

@@ -0,0 +1,9 @@
+import zhLocale from 'element-ui/lib/locale/lang/en'
+export default {
+  "lang": "中文",
+  // 导航
+  navigation: {
+    reports: "工时报告"
+  },
+  ...zhLocale
+}

+ 4 - 0
fhKeeper/formulahousekeeper/timesheet/src/main.js

@@ -26,6 +26,9 @@ import './day.js' // 加载 dayjs 初始化配置
 import dayjs from 'dayjs';
 Vue.prototype.dayjs = dayjs;
 
+// 引入中译英js
+import i18n from '@/i18n/index'
+
 import Viewer from 'v-viewer' // 图片预览
 import 'viewerjs/dist/viewer.css'
 // Vue.use(Viewer)
@@ -289,6 +292,7 @@ Vue.directive('enterNumber', {
 new Vue({
     router,
     store,
+    i18n,
     render: h => h(App)
 }).$mount('#app')
 

+ 28 - 9
fhKeeper/formulahousekeeper/timesheet/src/routes.js

@@ -116,7 +116,9 @@ export const fixedRouter = [
             { path: 'summary/:id', component: projectInside, name: '数据统计' },
             { path: 'costbaseline/:id', component: projectInside, name: '成本管理' },
             { path: 'earning/:id', component: projectInside, name: '挣值分析' },
-        ]
+        ],
+        // 其他信息
+        meta: { text: 'navigation.projectManagement' } 
     },
     {
         path: '/projectGantt',
@@ -138,11 +140,14 @@ export const allRouters = [//组织架构
         path: '/',
         component: Home,
         name: '工时报告',
+        text: 'navigation.reports',
         iconCls: 'iconfont firerock-icontianbao1',
         leaf: true,
         children: [
             { path: '/daily', component: daily, name: '工时报告' },
-        ]
+        ],
+        // 其他信息
+        meta: { text: 'reports' } 
     },
     // {
     //     path: '/',
@@ -163,7 +168,9 @@ export const allRouters = [//组织架构
         leaf: true,
         children: [
             { path: '/reviewProfession', component: reviewProfession, name: '专业审核' },
-        ]
+        ],
+        // 其他信息
+        meta: { text: 'navigation.professionalAudit' } 
     },
     {
         path: '/',
@@ -173,7 +180,9 @@ export const allRouters = [//组织架构
         leaf: true,
         children: [
             { path: '/reviewDepartment', component: reviewDepartment, name: '部门审核' },
-        ]
+        ],
+        // 其他信息
+        meta: { text: 'navigation.departmentAudit' } 
     },
     {
         path: '/',
@@ -183,7 +192,9 @@ export const allRouters = [//组织架构
         leaf: true,
         children: [
             { path: '/review', component: review, name: '项目报告审核' },
-        ]
+        ],
+        // 其他信息
+        meta: { text: 'navigation.projectReportReview' } 
     },
     {
         path: '/',
@@ -193,7 +204,9 @@ export const allRouters = [//组织架构
         leaf: true,
         children: [
             { path: '/reviewImport', component: reviewImport, name: '导入日报审核' },
-        ]
+        ],
+        // 其他信息
+        meta: { text: 'navigation.ImportDailyReview' } 
     },
     //成本统计
     {
@@ -206,7 +219,9 @@ export const allRouters = [//组织架构
             { path: '/cost', component: cost, name: '工时成本统计' },
             { path: '/cost/:id/:name', component: proDetail, name: '成本详情', hidden: true },
             { path: '/costDep/:id/:name', component: depDetail, name: '成本详情', hidden: true },
-        ]
+        ],
+        // 其他信息
+        meta: { text: 'navigation.laborCostStatistics' } 
     },
     //自定义数值统计
     {
@@ -217,7 +232,9 @@ export const allRouters = [//组织架构
         leaf: true,
         children: [
             { path: '/customData', component: customData, name: '自定义数值统计' }
-        ]
+        ],
+        // 其他信息
+        meta: { text: 'navigation.customizeNumericalStatistics' } 
     },
     
     //每月财务成本
@@ -229,7 +246,9 @@ export const allRouters = [//组织架构
         leaf: true,
         children: [
             { path: '/finance', component: finance, name: '财务核算成本' },
-        ]
+        ],
+        // 其他信息
+        meta: { text: 'navigation.financialAccountingCost' } 
     },
     // 任务管理
     {

+ 38 - 3
fhKeeper/formulahousekeeper/timesheet/src/views/Home.vue

@@ -14,7 +14,19 @@
                     <span style="position: absolute;width: 350px;left: 60px;">{{user.companyName}}</span>
                 </div>
             </el-col>
+
             <el-col :span="10" class="userinfo">
+                <!-- 中英文切换入口 -->
+                <!-- <el-dropdown trigger="click" @command="langChange" style="margin-right:30px;">
+                    <span class="el-dropdown-link userinfo-inner">
+                        {{language}} <i class="el-icon-caret-bottom"></i>
+                    </span>
+                    <el-dropdown-menu slot="dropdown">
+                        <el-dropdown-item divided  command="zh">中文</el-dropdown-item>
+                        <el-dropdown-item divided  command="en">English</el-dropdown-item>
+                    </el-dropdown-menu>
+                </el-dropdown> -->
+
                 <el-dropdown trigger="hover" style="margin-right:30px;">
                     <span class="el-dropdown-link userinfo-inner">
                         <i class="el-icon-user" style="font-size:18px" ></i>
@@ -69,23 +81,25 @@
                 </el-dropdown>
             </el-col>
         </el-col>
-
         <el-col :span="24" class="main">
 
             <aside :class="collapsed?'menu-collapsed':'menu-expanded'">
                 <el-scrollbar style="height:100%">
                 <!--导航菜单-->
                 <el-menu :default-active="$route.path" class="el-menu-vertical-demo" unique-opened router v-if="!collapsed">
-                    <template v-for="(item,index) in $router.options.routes" v-if="!item.hidden">
+                    <template v-for="(item, index) in $router.options.routes" v-if="!item.hidden">
                         <el-submenu :index="index+''" v-if="!item.leaf">
                             <template slot="title">
                                 <i :class="item.iconCls"></i>
+                                <!-- <span class="itemName">{{getTitle(item)}}</span> -->
                                 <span class="itemName">{{item.name}}</span>
                             </template>
                             <el-menu-item v-for="child in item.children" :index="child.path" :key="child.path" v-if="!child.hidden"><i :class="child.iconCls"></i>{{child.name}}</el-menu-item>
                         </el-submenu>
                         <el-menu-item v-if="item.leaf && item.children.length > 0" :index="item.children[0].path">
-                            <i :class="item.iconCls"></i> {{item.children[0].name}}
+                            <i :class="item.iconCls"></i> 
+                            {{item.children[0].name}}
+                            <!-- {{$t(item.text)}} -->
                         </el-menu-item>
                     </template>
                 </el-menu>
@@ -205,9 +219,22 @@
                 tableHeight: 0,
                 popoverData: [],
                 num: 0,
+
+                language: ''
             };
         },
         methods: {
+
+            // 中英文切换
+            langChange(command) {
+                this.$i18n.locale = command
+                localStorage.setItem("lang", command)
+                if(command == 'en') {
+                    this.language = 'English'
+                } else if (command == 'zh') {
+                    this.language = '中文'
+                }
+            },
             
             //退出登录
             logout: function() {
@@ -411,6 +438,14 @@
         },
         mounted() {
             // console.log(this.$router.options.routes, '看看')
+
+            let langse = localStorage.getItem("lang") || 'en'
+            if(langse == 'en') {
+                this.language = 'English'
+            } else if (langse == 'zh') {
+                this.language = '中文'
+            }
+
             let height = window.innerHeight;
             this.tableHeight = height - 15;
             const that = this;

+ 10 - 10
fhKeeper/formulahousekeeper/timesheet_h5/vue.config.js

@@ -4,19 +4,19 @@ const path = require('path');
 const themePath = path.resolve(__dirname,'src/assets/style/theme.less');
 const Timestamp = new Date().getTime();
 
-// var ip = '47.101.180.183'
+var ip = '47.101.180.183'
 // var ip = '192.168.2.7'
 // var ip = '127.0.0.1'
 
-var os = require('os'), ip = '', ifaces = os.networkInterfaces() // 获取本机ip
-for (var i in ifaces) {
-    for (var j in ifaces[i]) {
-        var val = ifaces[i][j]
-        if (val.family === 'IPv4' && val.address !== '127.0.0.1') {
-            ip = val.address
-        }
-    }
-}
+// var os = require('os'), ip = '', ifaces = os.networkInterfaces() // 获取本机ip
+// for (var i in ifaces) {
+//     for (var j in ifaces[i]) {
+//         var val = ifaces[i][j]
+//         if (val.family === 'IPv4' && val.address !== '127.0.0.1') {
+//             ip = val.address
+//         }
+//     }
+// }
 
 module.exports = {
     // 关闭eslint检查