├── .gitignore ├── .storybook ├── addons.js ├── config.js ├── manager-head.html ├── preview-head.html └── webpack.config.js ├── .tx └── config ├── LICENSE.md ├── README.md ├── babel.config.js ├── package.json ├── src ├── components │ ├── Account.vue │ ├── AccountDetails.vue │ ├── AccountList.vue │ ├── AccountRing.vue │ ├── AccountSelector.vue │ ├── AddressDisplay.vue │ ├── AddressInput.vue │ ├── Amount.vue │ ├── AmountInput.vue │ ├── AmountWithFee.vue │ ├── BottomOverlay.vue │ ├── Carousel.vue │ ├── CircleSpinner.vue │ ├── CloseButton.vue │ ├── Copyable.vue │ ├── CopyableField.vue │ ├── FiatAmount.vue │ ├── Icons.ts │ ├── Identicon.vue │ ├── LabelInput.vue │ ├── LanguageSelector.vue │ ├── LoadingSpinner.vue │ ├── LongPressButton.vue │ ├── PageBody.vue │ ├── PageFooter.vue │ ├── PageHeader.vue │ ├── PaymentInfoLine.vue │ ├── QrCode.vue │ ├── QrScanner.vue │ ├── SelectBar.vue │ ├── SliderToggle.vue │ ├── SmallPage.vue │ ├── Timer.vue │ ├── Tooltip.vue │ └── Wallet.vue ├── i18n │ ├── I18n.vue │ ├── I18nMixin.ts │ ├── de.po │ ├── en.po │ ├── es.po │ ├── fr.po │ ├── nl.po │ ├── pt.po │ ├── ru.po │ ├── uk.po │ └── zh.po ├── main.ts └── stories │ └── index.stories.js ├── tsconfig.json ├── tslint.json ├── types ├── index.d.ts └── svg.d.ts ├── vue.config.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | dist-storybook 5 | 6 | # generated json language files 7 | src/i18n/**/*.json 8 | 9 | # local env files 10 | .env.local 11 | .env.*.local 12 | 13 | # Log files 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | 18 | # Editor directories and files 19 | .idea 20 | .vscode 21 | *.suo 22 | *.ntvs* 23 | *.njsproj 24 | *.sln 25 | *.sw* 26 | *.iml 27 | -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import '@storybook/addon-knobs/register'; 2 | import "@storybook/addon-actions/register"; 3 | import "@storybook/addon-links/register"; 4 | import '@storybook/addon-viewport/register'; 5 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import { configure } from "@storybook/vue"; 2 | 3 | const req = require.context("../src/stories", true, /.stories.(js|ts)$/); 4 | 5 | function loadStories() { 6 | req.keys().forEach(filename => req(filename)); 7 | } 8 | 9 | configure(loadStories, module); 10 | -------------------------------------------------------------------------------- /.storybook/manager-head.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimiq/vue-components/e64b89ba0b4377c56510aad6744808352b4fa747/.storybook/manager-head.html -------------------------------------------------------------------------------- /.storybook/preview-head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | -------------------------------------------------------------------------------- /.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | // Fix build for Node version with OpenSSL 3 4 | const crypto = require('crypto'); 5 | const origCreateHash = crypto.createHash; 6 | crypto.createHash = (alg, opts) => { 7 | return origCreateHash(alg === 'md4' ? 'md5' : alg, opts); 8 | }; 9 | 10 | // Process source files and specified dependencies by babel to be able to use more modern js syntax than supported by 11 | // our Webpack version. Should be kept in sync with transpileDependencies in vue.config.js 12 | const transpileDependencies = ['@nimiq/utils']; 13 | const babel = { 14 | loader: require.resolve('babel-loader'), 15 | // By default, options from babel.config.js are used. If you're encountering issues with some syntax not being 16 | // transpiled sufficiently, experiment with different @vue/babel-preset-app or @babel/preset-env options. As this is 17 | // only for a demo page, the resulting file size by code being transpiled too aggressively or too many polyfills 18 | // being included, doesn't really matter. 19 | // options: { 20 | // presets: [ 21 | // ['@babel/preset-env', { 22 | // targets: { node: 14 }, 23 | // // useBuiltIns: 'usage', 24 | // // corejs: '3.37', 25 | // // include: ["@babel/plugin-transform-logical-assignment-operators"], 26 | // debug: true, 27 | // }] 28 | // ], 29 | // }, 30 | }; 31 | 32 | module.exports = (storybookBaseConfig, env, config) => { 33 | // Save and remove default SVG rule to add a custom one below 34 | const svgRule = config.module.rules.find(rule => rule.test.toString().includes('svg')); 35 | config.module.rules = config.module.rules.filter(rule => !rule.test.toString().includes('svg')); 36 | 37 | return { 38 | ...config, 39 | plugins: [...config.plugins, new (require('vue-loader/lib/plugin'))()], 40 | module: { 41 | ...config.module, 42 | rules: [...config.module.rules, { 43 | test: /\.tsx?$/, 44 | use: [babel, { 45 | loader: require.resolve('ts-loader'), 46 | options: { 47 | appendTsSuffixTo: [/\.vue$/], 48 | transpileOnly: true 49 | } 50 | }] 51 | }, { 52 | test: svgRule.test, 53 | oneOf: [{ 54 | // Add new icon SVG rule 55 | test: /icons/, 56 | loader: 'vue-svg-loader', 57 | options: { svgo: false } 58 | }, { 59 | // Re-add default SVG rule 60 | loader: svgRule.loader, 61 | options: svgRule.options 62 | }], 63 | }, { 64 | test: /\.(?:js|mjs|cjs)$/, 65 | include: [ 66 | 'src', // Process js files in src, basically index.stories.js 67 | ...transpileDependencies.map((dependency) => path.join('node_modules', dependency)), 68 | ].map((dependency) => path.join(__dirname, '..', dependency)), 69 | ...babel, 70 | }] 71 | }, 72 | resolve: { 73 | ...config.resolve, 74 | extensions: [...config.resolve.extensions, '.ts', '.tsx'] 75 | } 76 | }; 77 | }; 78 | -------------------------------------------------------------------------------- /.tx/config: -------------------------------------------------------------------------------- 1 | [main] 2 | host = https://www.transifex.com 3 | 4 | [o:nimiq-foundation:p:nimiq-vue-components:r:en-po] 5 | file_filter = src/i18n/.po 6 | source_file = src/i18n/en.po 7 | source_lang = en 8 | type = PO 9 | minimum_perc = 95 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nimiq vue-components 2 | 3 | This component library provides components written for the [Vue frontend framework](https://vuejs.org/) for use in Nimiq 4 | Ecosystem apps. Have a look at the [demo page](https://nimiq.github.io/vue-components/) for an overview of included 5 | components. 6 | 7 | ## Installation 8 | 9 | ```bash 10 | yarn add github:nimiq/vue-components#build/master 11 | ``` 12 | 13 | This will install the complete component collection. To install only a subset for reduced bundle size, see section 14 | [Advanced setup](#advanced-setup). 15 | 16 | Some components require additional lazy-loaded assets which have to be copied over to your project. Specifically, these 17 | are translation files (if you want to support other languages than English), the Identicon svg asset and the QR scanner 18 | worker. 19 | 20 | If your project has been created with the 21 | [vue-cli](https://cli.vuejs.org/) / gets bundled via [webpack](https://webpack.js.org/), this can be conveniently done 22 | with the [CopyWebpackPlugin](https://webpack.js.org/plugins/copy-webpack-plugin/): 23 | 24 | ```js 25 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 26 | 27 | const plugins = [ 28 | new CopyWebpackPlugin([ 29 | // for translation files and additional, unnamed js chunks (currently only the qr scanner worker) 30 | { 31 | from: 'node_modules/@nimiq/vue-components/dist/NimiqVueComponents.umd.min.+(lang-*|[0-9]).js', 32 | to: './', 33 | flatten: true, 34 | transformPath(path) { 35 | // If you are bundling a non-minified build of the components (for later minification in your build 36 | // process; the default) it tries to also load the the non-minified language files, but we want 37 | // to load the minified files instead, so we rename them. 38 | return path.replace('.min', ''); 39 | }, 40 | }, 41 | // for the identicons 42 | { 43 | from: 'node_modules/@nimiq/vue-components/dist/iqons.min.*.svg', 44 | to: './', 45 | flatten: true, 46 | }, 47 | ]), 48 | ... 49 | ]; 50 | 51 | // webpack.config.js: 52 | module.exports = { 53 | plugins, 54 | ... 55 | }; 56 | 57 | // Or for projects created via vue-cli: 58 | module.exports = { 59 | configureWebpack: { 60 | plugins, 61 | }, 62 | ... 63 | }; 64 | ``` 65 | 66 | By default, these assets are resolved relatively to the importing script's location (the importing script's 67 | currentScript src) as base path. Alternatively, you can also specify a custom path: 68 | 69 | ```js 70 | import { setAssetPublicPath } from '@nimiq/vue-components'; 71 | 72 | setAssetPublicPath('/my-path/'); 73 | 74 | // Useful for projects setup via vue-cli to apply the app's public path to the vue-component assets 75 | setAssetPublicPath(process.env.BASE_URL); 76 | 77 | // You can also specify a separate folder for image assets 78 | setAssetPublicPath('/js', '/img'); 79 | ``` 80 | 81 | ## Updating 82 | 83 | ```bash 84 | yarn upgrade @nimiq/vue-components 85 | ``` 86 | 87 | ## Usage 88 | 89 | Import the components you want to use in your Vue component and define them as child `components`, for example: 90 | 91 | ```js 92 | import { LoadingSpinner } from '@nimiq/vue-components'; 93 | 94 | Vue.component('my-component', { 95 | components: { LoadingSpinner }, 96 | template: ` 97 |
98 | Loading stuff... 99 | 100 |
101 | `, 102 | }); 103 | ``` 104 | 105 | ## Advanced Setup 106 | 107 | As this component library is built with webpack which does unfortunately currently not support outputting a 108 | tree-shakeable es6 module yet, we currently do not provide a package that supports tree-shaking and 109 | dead-code-elimination. To fix this, we will either wait for 110 | [es6 module output support to be added to webpack](https://github.com/webpack/webpack/issues/2933), switch to 111 | [building with rollup](https://github.com/nimiq/vue-components/issues/8) or release each component as separate package. 112 | 113 | Until then, you have two options for including only a subset of the components in your code to reduce your bundle size: 114 | 115 | 1. Import the unprocessed `.vue` single file components directly, for example `import LoadingSpinner from 116 | '@nimiq/vue-components/src/components/LoadingSpinner.vue'`. Note that for this to work, you need a bundler and build 117 | process that can handle `.vue` single file components and typescript. Also note that for some components additional 118 | setup might be required, for example for icon components imported from 119 | [Icons.ts](https://github.com/nimiq/vue-components/blob/master/src/components/Icons.ts) (see 120 | [vue.config.js](https://github.com/nimiq/vue-components/blob/master/vue.config.js)). 121 | 122 | 2. Create a custom build of the vue-components that only includes the components you need. To do this, follow these 123 | steps: 124 | 1. Fork this repository and `git clone` the fork to your computer. 125 | 2. Comment-out all components and icons in 126 | [main.ts](https://github.com/nimiq/vue-components/blob/master/src/main.ts) and 127 | [Icons.ts](https://github.com/nimiq/vue-components/blob/master/src/components/Icons.ts) that you do not need. 128 | 3. Build the source code via `yarn && yarn build`. 129 | 4. Remove `dist` from [.gitignore](https://github.com/nimiq/vue-components/blob/master/.gitignore), then `git add 130 | dist .gitignore` to add the build output to your repository. 131 | 5. Create a `git commit` and `git push` it to your fork respository. 132 | 6. In your project, include the vue components from your fork, i.e. `yarn add github:/vue-components` 134 | 135 | ## Development and testing 136 | 137 | To install dependencies run: 138 | ```bash 139 | yarn 140 | ``` 141 | 142 | To run the demo page locally with hot-reloading on changes to the code base: 143 | ```bash 144 | yarn storybook 145 | ``` 146 | 147 | To check for linting errors: 148 | ```bash 149 | yarn lint 150 | ``` 151 | 152 | To build the component library: 153 | ```bash 154 | yarn build 155 | ``` 156 | 157 | ## Internationalization 158 | 159 | First of all, a big thank you to all translators! 160 | 161 | The Nimiq Vue-components are fully internationalized and ready for the community to add translations in different languages. 162 | 163 | To help translate Vue-components, the procedure is as follows: 164 | - Clone this repository. 165 | 166 | - The translations are located in the `src/i18n` folder. A translation file for a language is named as the language's 167 | two letter [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) plus file extension `.po`. For 168 | example, for French with two letter code `fr` the translations are located at `src/i18n/fr.po`. If that file doesn't 169 | exist yet, i.e. you're starting a new translation, please duplicate `en.po` as starting point, rename it 170 | accordingly and then add the language to the `SUPPORTED_LANGUAGES` in `I18nMixin.ts`. 171 | 172 | - In the language files, the source strings to be translated are between double quotes after the word `msgid`. 173 | For Example: 174 | ``` 175 | msgid "Account Created" 176 | ``` 177 | The translations of these must be provided in the same way, following the word `msgstr`. For Example: 178 | ``` 179 | msgid "Account Created" 180 | msgstr "Compte Créé" 181 | ``` 182 | Please only edit the translations, not the source strings. 183 | 184 | - Please also don't change the `.json` language files as these are auto-generated. Only edit the `.po` language files. 185 | 186 | - You can test your translations locally by running the demo page as described in section 187 | [Development and testing](#development-and-testing) and then setting a language cookie in the served page. To do so, 188 | open your browser's developer console (ctrl + shift + c) and input `document.cookie = 'lang='` where `` 189 | should be replaced by the two letter language code of the language you want to test, for example `document.cookie = 190 | 'lang=fr'`. After reloading the page, the components should be displayed in your chosen language. Note that the demos 191 | themselves are not translated, only the components. If you struggle setting up the local demo you can ask us to setup 192 | an online demo for you after opening a pull request. 193 | 194 | - Once the file has been fully translated or you are done updating an existing language file, you can open a pull 195 | request here in github. 196 | 197 | - The pull request will then be reviewed and, if all goes well, merged into the master branch and published asap. 198 | 199 | #### Additional information 200 | 201 | - Multiline translations are possible by inserting line breaks as `\n`. For example: 202 | ``` 203 | msgid "" 204 | "Imagine if paying with\n" 205 | "crypto was easy" 206 | msgstr "" 207 | "Imaginez si payer avec\n" 208 | "de la crypto était facile." 209 | ``` 210 | Please only insert line breaks into translations for source strings which already include a line break. Otherwise, 211 | they might break the layout of the component or not work as intended. 212 | 213 | - Words between curly brackets are variables which must not be translated nor edited. They will be replaced by a value 214 | during app runtime. The name of the variable should be obvious enough for you to understand what it will be replaced 215 | by so you can place it at the right position in the translated string. For example: 216 | ``` 217 | msgid "Cancel {payment}" 218 | msgstr "Annuler {payment}" 219 | ``` 220 | 221 | - If you're a transifex collaborator, and need some information about how to get started, here are two links for you: 222 | - How to get started as a translator: https://docs.transifex.com/getting-started-1/translators 223 | - How translate using the web editor: https://docs.transifex.com/translation/translating-with-the-web-editor 224 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nimiq/vue-components", 3 | "version": "0.1.0", 4 | "author": "Nimiq", 5 | "scripts": { 6 | "build": "yarn i18n:extract && yarn i18n:lib && vue-cli-service build --target lib --name NimiqVueComponents src/main.ts", 7 | "lint": "vue-cli-service lint", 8 | "storybook": "yarn i18n:extract && yarn i18n:lib && start-storybook -p 6006 -c .storybook -s .", 9 | "build-storybook": "build-storybook -c .storybook -o dist-storybook", 10 | "update-browserslist": "yarn update-browserslist-db", 11 | "i18n:extract": "node ./node_modules/webpack-i18n-tools/index.js ./src/i18n/en.po", 12 | "i18n:pull": "tx pull --force --all", 13 | "i18n:push": "tx push --source", 14 | "i18n:lib": "rimraf src/i18n/?? ; node node_modules/webpack-i18n-tools/tools/convertToJsonLib.js 'src/i18n/!(en).po'", 15 | "i18n:sync": "yarn i18n:extract && yarn i18n:push && yarn i18n:pull && yarn i18n:lib" 16 | }, 17 | "main": "dist/NimiqVueComponents.common.js", 18 | "module": "dist/NimiqVueComponents.umd.js", 19 | "files": [ 20 | "dist/**/*", 21 | "types/**/*" 22 | ], 23 | "dependencies": { 24 | "@nimiq/iqons": "^1.6.0", 25 | "@nimiq/style": "^0.8.5", 26 | "@nimiq/utils": "^0.11.1", 27 | "big-integer": "^1.6.44", 28 | "input-format": "^0.2.8", 29 | "js-sha3": "^0.8.0", 30 | "qr-creator": "^1.0.0", 31 | "qr-scanner": "^1.4.2", 32 | "vue": "^2.6.11", 33 | "vue-property-decorator": "^8.4.0" 34 | }, 35 | "devDependencies": { 36 | "@storybook/addon-actions": "^4.0.0-alpha.14", 37 | "@storybook/addon-knobs": "^4.0.0-alpha.14", 38 | "@storybook/addon-links": "^4.0.0-alpha.14", 39 | "@storybook/addon-viewport": "^4.0.0-alpha.14", 40 | "@storybook/vue": "^4.0.0-alpha.14", 41 | "@vue/cli-plugin-babel": "~4.5.19", 42 | "@vue/cli-plugin-typescript": "~4.5.19", 43 | "@vue/cli-service": "~4.5.19", 44 | "@vue/compiler-dom": "^3.2.45", 45 | "core-js": "^3.37.1", 46 | "file-loader": "^3.0.1", 47 | "moment": "^2.29.4", 48 | "rimraf": "^3.0.2", 49 | "typescript": "~3.7.5", 50 | "vue-cli-plugin-ts-bundler": "^0.0.3", 51 | "vue-svg-loader": "^0.12.0", 52 | "vue-template-compiler": "^2.6.11", 53 | "webpack-i18n-tools": "https://github.com/nimiq/webpack-i18n-tools#master" 54 | }, 55 | "eslintConfig": { 56 | "root": true, 57 | "env": { 58 | "node": true 59 | }, 60 | "extends": [ 61 | "plugin:vue/essential", 62 | "eslint:recommended" 63 | ], 64 | "rules": {}, 65 | "parserOptions": { 66 | "parser": "babel-eslint" 67 | } 68 | }, 69 | "postcss": { 70 | "plugins": { 71 | "autoprefixer": {} 72 | } 73 | }, 74 | "browserslist": [ 75 | "> 1%", 76 | "last 2 versions", 77 | "not ie <= 10" 78 | ], 79 | "license": "Apache-2.0", 80 | "types": "types/index.d.ts", 81 | "packageManager": "yarn@1.22.19" 82 | } 83 | -------------------------------------------------------------------------------- /src/components/Account.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 74 | 75 | 209 | -------------------------------------------------------------------------------- /src/components/AccountDetails.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 43 | 44 | 102 | -------------------------------------------------------------------------------- /src/components/AccountList.vue: -------------------------------------------------------------------------------- 1 | 50 | 51 | 150 | 151 | 255 | -------------------------------------------------------------------------------- /src/components/AccountRing.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 22 | 23 | 92 | -------------------------------------------------------------------------------- /src/components/AddressDisplay.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 58 | 59 | 105 | -------------------------------------------------------------------------------- /src/components/Amount.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 83 | 84 | 94 | -------------------------------------------------------------------------------- /src/components/AmountInput.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 108 | 109 | 166 | -------------------------------------------------------------------------------- /src/components/AmountWithFee.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 70 | 71 | 104 | -------------------------------------------------------------------------------- /src/components/BottomOverlay.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 38 | 39 | 115 | -------------------------------------------------------------------------------- /src/components/CircleSpinner.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 19 | -------------------------------------------------------------------------------- /src/components/CloseButton.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | 20 | 49 | -------------------------------------------------------------------------------- /src/components/Copyable.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 79 | 80 | 160 | -------------------------------------------------------------------------------- /src/components/CopyableField.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 107 | 108 | 239 | -------------------------------------------------------------------------------- /src/components/FiatAmount.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 136 | -------------------------------------------------------------------------------- /src/components/Icons.ts: -------------------------------------------------------------------------------- 1 | import { VueConstructor, CreateElement, RenderContext } from 'vue'; 2 | 3 | // See https://vuejs.org/v2/guide/render-function.html for documentation on createElement and functional components 4 | // tslint:disable-next-line:variable-name 5 | const IconBase = (component: VueConstructor) => ({ 6 | functional: true, 7 | render(createElement: CreateElement, context: RenderContext) { 8 | return createElement(component, Object.assign({ class: 'nq-icon' }, context.data)); 9 | }, 10 | } as any); // Should be FunctionalComponentOptions (imported from 'vue'), but as such cannot be imported in accounts... 11 | 12 | /** 13 | * SVG files in an /icons/ directory are automatically loaded as Vue components 14 | * via the vue-svg-loader. 15 | */ 16 | import AlertCircle from '@nimiq/style/src/icons/alert-circle.svg'; 17 | import AlertTriangle from '@nimiq/style/src/icons/alert-triangle.svg'; 18 | import ArrowLeftSmall from '@nimiq/style/src/icons/arrow-left-small.svg'; 19 | import ArrowLeft from '@nimiq/style/src/icons/arrow-left.svg'; 20 | import ArrowRightSmall from '@nimiq/style/src/icons/arrow-right-small.svg'; 21 | import ArrowRight from '@nimiq/style/src/icons/arrow-right.svg'; 22 | import CaretRightSmall from '@nimiq/style/src/icons/caret-right-small.svg'; 23 | import Cashlink from '@nimiq/style/src/icons/cashlink.svg'; 24 | import CashlinkSmall from '@nimiq/style/src/icons/cashlink-small.svg'; 25 | import CashlinkXSmall from '@nimiq/style/src/icons/cashlink-xsmall.svg'; 26 | import Checkmark from '@nimiq/style/src/icons/checkmark.svg'; 27 | import CheckmarkSmall from '@nimiq/style/src/icons/checkmark-small.svg'; 28 | import Close from '@nimiq/style/src/icons/close.svg'; 29 | import Contacts from '@nimiq/style/src/icons/contacts.svg'; 30 | import Copy from '@nimiq/style/src/icons/copy.svg'; 31 | import Cross from '@nimiq/style/src/icons/cross.svg'; 32 | import Download from '@nimiq/style/src/icons/download.svg'; 33 | import FaceNeutral from '@nimiq/style/src/icons/face-neutral.svg'; 34 | import FaceSad from '@nimiq/style/src/icons/face-sad.svg'; 35 | import Gear from '@nimiq/style/src/icons/gear.svg'; 36 | import Hexagon from '@nimiq/style/src/icons/hexagon.svg'; 37 | import InfoCircle from '@nimiq/style/src/icons/info-circle.svg'; 38 | import InfoCircleSmall from '@nimiq/style/src/icons/info-circle-small.svg'; 39 | import Keys from '@nimiq/style/src/icons/keys.svg'; 40 | import Ledger from '@nimiq/style/src/icons/ledger.svg'; 41 | import LockLocked from '@nimiq/style/src/icons/lock-locked.svg'; 42 | import LockUnlocked from '@nimiq/style/src/icons/lock-unlocked.svg'; 43 | import Login from '@nimiq/style/src/icons/login.svg'; 44 | import MenuDots from '@nimiq/style/src/icons/menu-dots.svg'; 45 | import PlusCircle from '@nimiq/style/src/icons/plus-circle.svg'; 46 | import QrCode from '@nimiq/style/src/icons/qr-code.svg'; 47 | import Questionmark from '@nimiq/style/src/icons/questionmark.svg'; 48 | import ScanQrCode from '@nimiq/style/src/icons/scan-qr-code.svg'; 49 | import Settings from '@nimiq/style/src/icons/settings.svg'; 50 | import Stopwatch from '@nimiq/style/src/icons/stopwatch.svg'; 51 | import Transfer from '@nimiq/style/src/icons/transfer.svg'; 52 | import UnderPayment from '@nimiq/style/src/icons/under-payment.svg'; 53 | import ViewOff from '@nimiq/style/src/icons/view-off.svg'; 54 | import View from '@nimiq/style/src/icons/view.svg'; 55 | 56 | /** 57 | * Comment out any unused icons here 58 | */ 59 | // tslint:disable:variable-name 60 | export const AlertCircleIcon = IconBase(AlertCircle); 61 | export const AlertTriangleIcon = IconBase(AlertTriangle); 62 | export const ArrowLeftSmallIcon = IconBase(ArrowLeftSmall); 63 | export const ArrowLeftIcon = IconBase(ArrowLeft); 64 | export const ArrowRightSmallIcon = IconBase(ArrowRightSmall); 65 | export const ArrowRightIcon = IconBase(ArrowRight); 66 | export const CaretRightSmallIcon = IconBase(CaretRightSmall); 67 | export const CashlinkIcon = IconBase(Cashlink); 68 | export const CashlinkSmallIcon = IconBase(CashlinkSmall); 69 | export const CashlinkXSmallIcon = IconBase(CashlinkXSmall); 70 | export const CheckmarkIcon = IconBase(Checkmark); 71 | export const CheckmarkSmallIcon = IconBase(CheckmarkSmall); 72 | export const CloseIcon = IconBase(Close); 73 | export const ContactsIcon = IconBase(Contacts); 74 | export const CopyIcon = IconBase(Copy); 75 | export const CrossIcon = IconBase(Cross); 76 | export const DownloadIcon = IconBase(Download); 77 | export const FaceNeutralIcon = IconBase(FaceNeutral); 78 | export const FaceSadIcon = IconBase(FaceSad); 79 | export const GearIcon = IconBase(Gear); 80 | export const HexagonIcon = IconBase(Hexagon); 81 | export const InfoCircleIcon = IconBase(InfoCircle); 82 | export const InfoCircleSmallIcon = IconBase(InfoCircleSmall); 83 | export const KeysIcon = IconBase(Keys); 84 | export const LedgerIcon = IconBase(Ledger); 85 | export const LockLockedIcon = IconBase(LockLocked); 86 | export const LockUnlockedIcon = IconBase(LockUnlocked); 87 | export const LoginIcon = IconBase(Login); 88 | export const MenuDotsIcon = IconBase(MenuDots); 89 | export const PlusCircleIcon = IconBase(PlusCircle); 90 | export const QrCodeIcon = IconBase(QrCode); 91 | export const QuestionmarkIcon = IconBase(Questionmark); 92 | export const ScanQrCodeIcon = IconBase(ScanQrCode); 93 | export const SettingsIcon = IconBase(Settings); 94 | export const StopwatchIcon = IconBase(Stopwatch); 95 | export const TransferIcon = IconBase(Transfer); 96 | export const UnderPaymentIcon = IconBase(UnderPayment); 97 | export const ViewOffIcon = IconBase(ViewOff); 98 | export const ViewIcon = IconBase(View); 99 | // tslint:enable:variable-name 100 | -------------------------------------------------------------------------------- /src/components/Identicon.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 63 | 64 | 74 | -------------------------------------------------------------------------------- /src/components/LabelInput.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 99 | 100 | 129 | -------------------------------------------------------------------------------- /src/components/LanguageSelector.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 105 | 106 | 209 | -------------------------------------------------------------------------------- /src/components/LoadingSpinner.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 15 | 16 | 50 | -------------------------------------------------------------------------------- /src/components/LongPressButton.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 83 | 84 | 191 | -------------------------------------------------------------------------------- /src/components/PageBody.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | 14 | 20 | -------------------------------------------------------------------------------- /src/components/PageFooter.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | 14 | 26 | -------------------------------------------------------------------------------- /src/components/PageHeader.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 37 | 38 | 112 | -------------------------------------------------------------------------------- /src/components/QrCode.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 113 | -------------------------------------------------------------------------------- /src/components/SelectBar.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 56 | 57 | 92 | -------------------------------------------------------------------------------- /src/components/SliderToggle.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 139 | 140 | 251 | 252 | -------------------------------------------------------------------------------- /src/components/SmallPage.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | 14 | 25 | -------------------------------------------------------------------------------- /src/components/Wallet.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 101 | 102 | 264 | -------------------------------------------------------------------------------- /src/i18n/I18n.vue: -------------------------------------------------------------------------------- 1 | 50 | -------------------------------------------------------------------------------- /src/i18n/I18nMixin.ts: -------------------------------------------------------------------------------- 1 | import { Cookie } from '@nimiq/utils'; 2 | import { Vue, Component } from 'vue-property-decorator'; 3 | 4 | type I18n$tVariables = { [key: string]: string | number } | any[]; 5 | 6 | /** 7 | * i18n mixin for vue-components that provides a similar, but reduced, api as vue-i18n. This is to avoid that users need 8 | * to add the entire vue-i18n lib to their app as soon as they want to use a component from this library even if they 9 | * don't intend to add internationalization. 10 | */ 11 | @Component 12 | class I18nMixin extends Vue { 13 | private static readonly DEFAULT_LANGUAGE = 'en'; 14 | private static readonly SUPPORTED_LANGUAGES = [ 15 | I18nMixin.DEFAULT_LANGUAGE, 16 | 'de', 'es', 'fr', 'nl', 'pt', 'ru', 'uk', 'zh', 17 | ]; 18 | 19 | /** Current active language */ 20 | private static lang: string = I18nMixin.detectLanguage(); 21 | private static readonly loadedMessages: { [lang: string]: { [key: string]: string } } = {}; 22 | private static readonly registeredComponents: { [componentName: string]: Set } = {}; 23 | 24 | /** 25 | * Set the language to use. This will lazy-load the translation files and rerender the ui once ready. 26 | * @param {string} lang - The language to use. 27 | */ 28 | public static setLanguage(lang: string) { 29 | // If the language is not supported set it to the default one 30 | if (!I18nMixin.SUPPORTED_LANGUAGES.includes(lang)) { 31 | lang = I18nMixin.DEFAULT_LANGUAGE; 32 | } 33 | if (lang === I18nMixin.lang) return; 34 | 35 | I18nMixin.lang = lang; 36 | for (const componentName of Object.keys(I18nMixin.registeredComponents)) { 37 | I18nMixin.loadComponentLanguageFile(componentName); 38 | } 39 | } 40 | 41 | /** 42 | * Detect the language to use. If no language is set fallback to the browser language. 43 | * @returns {string} The language code 44 | */ 45 | public static detectLanguage(): string { 46 | const langCookie = Cookie.getCookie('lang'); 47 | // const fallbackLang = window.navigator.language.split('-')[0]; 48 | const fallbackLang = 'en'; // TODO just temporarily, until language switching is enabled in wallet 49 | 50 | let lang = langCookie || fallbackLang; 51 | // If the language is not supported set it to the default one 52 | if (!I18nMixin.SUPPORTED_LANGUAGES.includes(lang)) { 53 | lang = I18nMixin.DEFAULT_LANGUAGE; 54 | } 55 | return lang; 56 | } 57 | 58 | /** 59 | * Get the translation of a given string for a component. 60 | * @param {string} componentName - Name of the component you want the translation for 61 | * @param {string} key - The string you want the translation for 62 | * @param {I18n$tVariables} [variables] - Variables to be replaced in the translated string. Optional. 63 | * @returns {string} The translated string. 64 | */ 65 | public static $t(componentName: string, key: string, variables?: I18n$tVariables): string; 66 | /** 67 | * Get the translation of a given string for a component. 68 | * @param {string} componentName - Name of the component you want the translation for 69 | * @param {string} key - The string you want the translation for 70 | * @param {string} lang - Language to use. The language has to be already loaded. 71 | * @param {I18n$tVariables} [variables] - Variables to be replaced in the translated string. Optional. 72 | * @returns {string} The translated string. 73 | */ 74 | public static $t(componentName: string, key: string, lang: string, variables?: I18n$tVariables): string; 75 | public static $t( 76 | componentName: string, 77 | key: string, 78 | variablesOrLang?: I18n$tVariables | string, 79 | variables?: I18n$tVariables, 80 | ): string { 81 | let lang; 82 | if (typeof variablesOrLang === 'string') { 83 | lang = variablesOrLang; 84 | } else { 85 | lang = I18nMixin.lang; 86 | variables = variablesOrLang; 87 | } 88 | const componentLang = `${lang}-${componentName}`; 89 | 90 | let message = I18nMixin.loadedMessages[componentLang] 91 | ? I18nMixin.loadedMessages[componentLang][key] || key 92 | : key; 93 | 94 | if (typeof variables === 'object' || Array.isArray(variables)) { 95 | message = message.replace(/{(\w+?)}/g, (match, variable) => variables[variable].toString() || match); 96 | } 97 | 98 | return message; 99 | } 100 | 101 | private static registerComponent(component: Vue) { 102 | const componentName = component.$options.name; 103 | // Using $options.name instead of constructor.name as class names get mangled in the production build. 104 | 105 | let componentsOfSameType = I18nMixin.registeredComponents[componentName]; 106 | if (!componentsOfSameType) { 107 | componentsOfSameType = new Set(); 108 | I18nMixin.registeredComponents[componentName] = componentsOfSameType; 109 | I18nMixin.loadComponentLanguageFile(componentName); 110 | } 111 | componentsOfSameType.add(component); 112 | } 113 | 114 | private static unregisterComponent(component: Vue) { 115 | const componentName = component.$options.name; 116 | // Using $options.name instead of constructor.name as class names get mangled in the production build. 117 | 118 | const componentsOfSameType = I18nMixin.registeredComponents[componentName]; 119 | if (!componentsOfSameType) return; 120 | if (componentsOfSameType.size === 1) { 121 | delete I18nMixin.registeredComponents[componentName]; 122 | } else { 123 | componentsOfSameType.delete(component); 124 | } 125 | } 126 | 127 | /** 128 | * Asynchronously load a translation file. 129 | * @param {string} componentName - Name of the component you want to load a translation for 130 | */ 131 | private static async loadComponentLanguageFile(componentName: string) { 132 | const lang = I18nMixin.lang; 133 | const componentLang = lang + '-' + componentName; 134 | 135 | if (!(componentLang in I18nMixin.loadedMessages) && lang !== 'en') { 136 | // Lazy-load translations. For English we don't load a language file but use the translation keys directly. 137 | // Note that the request is cached and not repeated for parallel calls. 138 | const messages = await import( 139 | // tslint:disable-next-line: trailing-comma 140 | /* webpackChunkName: "lang-[request]" */ `./${lang}/${componentName}.json` 141 | ); 142 | 143 | I18nMixin.loadedMessages[componentLang] = messages.default || {}; 144 | } 145 | 146 | const componentsToNotify = I18nMixin.registeredComponents[componentName] || []; 147 | for (const component of componentsToNotify) { 148 | // rerender with new language and notify potential event listeners 149 | component.$forceUpdate(); 150 | component.$emit(I18nMixin.Events.LANGUAGE_READY, lang); 151 | } 152 | } 153 | 154 | /* tslint:disable:jsdoc-format */ 155 | /** 156 | * Get the translation of a given string for this component. 157 | * @param {string} key - The string you want the translation for 158 | * @param {I18n$tVariables} [variables] - Variables to be replaced in the translated string. Optional. 159 | * @returns {string} The translated string. 160 | *//** 161 | * Get the translation of a given string for this component. 162 | * @param {string} key - The string you want the translation for 163 | * @param {string} lang - Language to use. The language has to be already loaded. 164 | * @param {I18n$tVariables} [variables] - Variables to be replaced in the translated string. Optional. 165 | * @returns {string} The translated string. 166 | */ 167 | /* tslint:enable:jsdoc-format */ 168 | // declared as property instead of instance member function for type compatibility with vue-i18n 169 | public $t: (key: string, variablesOrLang?: I18n$tVariables | string, variables?: I18n$tVariables) => string; 170 | 171 | protected beforeCreate() { 172 | this.$t = I18nMixin.$t.bind(this, this.$options.name); 173 | 174 | I18nMixin.registerComponent(this); 175 | } 176 | 177 | protected beforeDestroy() { 178 | I18nMixin.unregisterComponent(this); 179 | } 180 | } 181 | 182 | namespace I18nMixin { 183 | export enum Events { 184 | LANGUAGE_READY = 'language-ready', 185 | } 186 | } 187 | 188 | // Update the language in case it was changed via language cookie. 189 | window.addEventListener('focus', () => I18nMixin.setLanguage(I18nMixin.detectLanguage())); 190 | 191 | export default I18nMixin; 192 | -------------------------------------------------------------------------------- /src/i18n/de.po: -------------------------------------------------------------------------------- 1 | # 2 | # Translators: 3 | # Sven , 2020 4 | # Sebastian Langer , 2020 5 | # Redexe , 2020 6 | # Huriye , 2021 7 | # Daniel, 2024 8 | # 9 | msgid "" 10 | msgstr "" 11 | "Last-Translator: Daniel, 2024\n" 12 | "Language-Team: German (https://app.transifex.com/nimiq-foundation/teams/110181/de/)\n" 13 | "Content-Type: text/plain; charset=UTF-8\n" 14 | "Language: de\n" 15 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 16 | 17 | #: src/components/PaymentInfoLine.vue:77 18 | msgid "{amount} suggested network fee" 19 | msgstr "{amount} empfohlene Netzwerkgebühr" 20 | 21 | #: src/components/AccountSelector.vue:24 22 | msgid "{type} accounts cannot be used for this operation." 23 | msgstr "{type}-Konten können für diese Aktion nicht verwendet werden." 24 | 25 | #: src/components/QrScanner.vue:11 26 | msgid "Cancel" 27 | msgstr "Abbrechen" 28 | 29 | #: src/components/Wallet.vue:24 30 | msgid "Change Password" 31 | msgstr "Passwort ändern" 32 | 33 | #: src/components/QrScanner.vue:24 34 | msgid "" 35 | "Click on {icon} and go to\n" 36 | "Settings > Site Settings > Camera" 37 | msgstr "" 38 | "Klicke auf {icon} und gehe zu\n" 39 | "Einstellungen > Seiteneinstellungen > Kamera" 40 | 41 | #: src/components/QrScanner.vue:44 42 | msgid "Click on {icon} in the URL bar." 43 | msgstr "Klicke auf {icon} in der Adressleiste." 44 | 45 | #: src/components/QrScanner.vue:39 46 | msgid "" 47 | "Click on {safari} and go to\n" 48 | "Settings for this Website > Camera" 49 | msgstr "" 50 | "Klicke auf {safari} und gehe zu\n" 51 | "Einstellungen für Websites > Kamera" 52 | 53 | #: src/components/AccountList.vue:43 54 | msgid "Contracts cannot be used for this operation." 55 | msgstr "Smart-Contracts können für diese Aktion nicht verwendet werden." 56 | 57 | #: src/components/Copyable.vue:5 src/components/CopyableField.vue:20 58 | msgid "Copied" 59 | msgstr "Kopiert" 60 | 61 | #: src/components/Wallet.vue:21 62 | msgid "Create Backup" 63 | msgstr "Backup erstellen" 64 | 65 | #: src/components/Timer.vue:96 66 | msgid "day" 67 | msgstr "Tag" 68 | 69 | #: src/components/Timer.vue:97 70 | msgid "days" 71 | msgstr "Tage" 72 | 73 | #: src/components/PaymentInfoLine.vue:45 74 | msgid "Effective rate" 75 | msgstr "Effektiver Wechselkurs" 76 | 77 | #: src/components/AmountWithFee.vue:11 78 | msgid "fee" 79 | msgstr "Gebühr" 80 | 81 | #: src/components/PageHeader.vue:7 82 | msgid "Go back" 83 | msgstr "Zurück" 84 | 85 | #: src/components/QrScanner.vue:34 86 | msgid "Grant camera access when asked." 87 | msgstr "Bestätige den Zugriff auf deine Kamera, wenn du danach gefragt wirst." 88 | 89 | #: src/components/Timer.vue:94 90 | msgid "hour" 91 | msgstr "Stunde" 92 | 93 | #: src/components/Timer.vue:95 94 | msgid "hours" 95 | msgstr "Stunden" 96 | 97 | #: src/components/AmountWithFee.vue:5 98 | msgid "Insufficient balance" 99 | msgstr "Dein Guthaben reicht nicht aus." 100 | 101 | #: src/components/LongPressButton.vue:20 102 | msgid "Keep pressing…" 103 | msgstr "Halten…" 104 | 105 | #: src/components/AccountSelector.vue:202 106 | msgid "Legacy" 107 | msgstr "Legacy" 108 | 109 | #: src/components/AccountSelector.vue:47 110 | msgid "Login to another account" 111 | msgstr "In ein anderes Konto einloggen" 112 | 113 | #: src/components/Wallet.vue:26 114 | msgid "Logout" 115 | msgstr "Ausloggen" 116 | 117 | #: src/components/Timer.vue:92 118 | msgid "minute" 119 | msgstr "Minute" 120 | 121 | #: src/components/Timer.vue:93 122 | msgid "minutes" 123 | msgstr "Minuten" 124 | 125 | #: src/components/LabelInput.vue:4 src/components/LabelInput.vue:8 126 | msgid "Name your address" 127 | msgstr "Benenne deine Adresse" 128 | 129 | #: src/components/PaymentInfoLine.vue:88 130 | msgid "network fee" 131 | msgstr "Netzwerkgebühr" 132 | 133 | #: src/components/PaymentInfoLine.vue:60 134 | msgid "Nimiq provides this service free of charge." 135 | msgstr "Nimiq bietet diesen Service kostenlos an." 136 | 137 | #: src/components/PaymentInfoLine.vue:37 138 | msgid "Order amount" 139 | msgstr "Kaufbetrag" 140 | 141 | #: src/components/Wallet.vue:23 142 | msgid "Rename" 143 | msgstr "Umbenennen" 144 | 145 | #: src/components/Wallet.vue:18 146 | msgid "Save Login File" 147 | msgstr "Login-Datei speichern" 148 | 149 | #: src/components/Timer.vue:90 150 | msgid "second" 151 | msgstr "Sekunde" 152 | 153 | #: src/components/Timer.vue:91 154 | msgid "seconds" 155 | msgstr "Sekunden" 156 | 157 | #: src/components/QrScanner.vue:48 158 | msgid "the camera icon" 159 | msgstr "das Kamera-Symbol" 160 | 161 | #: src/components/AccountList.vue:44 162 | msgid "This address cannot be used for this operation." 163 | msgstr "Diese Adresse kann für diese Aktion nicht verwendet werden." 164 | 165 | #: src/components/Timer.vue:45 166 | msgid "This offer expires in {timer}." 167 | msgstr "Dieses Angebot endet in {timer}." 168 | 169 | #: src/components/PaymentInfoLine.vue:63 170 | msgid "Total" 171 | msgstr "Gesamt" 172 | 173 | #: src/components/QrScanner.vue:20 174 | msgid "Unblock the camera for this website to scan QR codes." 175 | msgstr "Erlaube den Zugriff auf deine Kamera, um QR-Codes zu scannen." 176 | 177 | #: src/components/PaymentInfoLine.vue:41 178 | msgid "Vendor crypto discount" 179 | msgstr "Krypto-Rabatt des Verkäufers" 180 | 181 | #: src/components/PaymentInfoLine.vue:40 182 | msgid "Vendor crypto markup" 183 | msgstr "Krypto-Aufschlag des Verkäufers" 184 | 185 | #: src/components/PaymentInfoLine.vue:291 186 | msgid "" 187 | "You are paying approx. {formattedRateDeviation} less than at the current " 188 | "market rate ({provider})." 189 | msgstr "" 190 | "Du zahlst etwa {formattedRateDeviation} weniger als zum aktuellen " 191 | "Wechselkurs ({provider})." 192 | 193 | #: src/components/PaymentInfoLine.vue:285 194 | msgid "" 195 | "You are paying approx. {formattedRateDeviation} more than at the current " 196 | "market rate ({provider})." 197 | msgstr "" 198 | "Du zahlst etwa {formattedRateDeviation} mehr als zum aktuellen Wechselkurs " 199 | "({provider})." 200 | 201 | #: src/components/PaymentInfoLine.vue:277 202 | msgid "" 203 | "Your actual discount is approx. {formattedRateDeviation} compared to the " 204 | "current market rate ({provider})." 205 | msgstr "" 206 | "Dein tatsächlicher Rabatt beträgt etwa {formattedRateDeviation} im Vergleich" 207 | " zum aktuellen Wechselkurs ({provider})." 208 | 209 | #: src/components/QrScanner.vue:16 210 | msgid "Your device does not have an accessible camera." 211 | msgstr "Dein Endgerät verfügt über keine verwendbare Kamera." 212 | -------------------------------------------------------------------------------- /src/i18n/en.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Content-Type: text/plain; charset=UTF-8\n" 4 | 5 | #: src/components/PaymentInfoLine.vue:77 6 | msgid "{amount} suggested network fee" 7 | msgstr "" 8 | 9 | #: src/components/AccountSelector.vue:24 10 | msgid "{type} accounts cannot be used for this operation." 11 | msgstr "" 12 | 13 | #: src/components/QrScanner.vue:11 14 | msgid "Cancel" 15 | msgstr "" 16 | 17 | #: src/components/Wallet.vue:24 18 | msgid "Change Password" 19 | msgstr "" 20 | 21 | #: src/components/QrScanner.vue:24 22 | msgid "" 23 | "Click on {icon} and go to\n" 24 | "Settings > Site Settings > Camera" 25 | msgstr "" 26 | 27 | #: src/components/QrScanner.vue:44 28 | msgid "Click on {icon} in the URL bar." 29 | msgstr "" 30 | 31 | #: src/components/QrScanner.vue:39 32 | msgid "" 33 | "Click on {safari} and go to\n" 34 | "Settings for this Website > Camera" 35 | msgstr "" 36 | 37 | #: src/components/AccountList.vue:43 38 | msgid "Contracts cannot be used for this operation." 39 | msgstr "" 40 | 41 | #: src/components/Copyable.vue:5 42 | #: src/components/CopyableField.vue:20 43 | msgid "Copied" 44 | msgstr "" 45 | 46 | #: src/components/Wallet.vue:21 47 | msgid "Create Backup" 48 | msgstr "" 49 | 50 | #: src/components/Timer.vue:96 51 | msgid "day" 52 | msgstr "" 53 | 54 | #: src/components/Timer.vue:97 55 | msgid "days" 56 | msgstr "" 57 | 58 | #: src/components/PaymentInfoLine.vue:45 59 | msgid "Effective rate" 60 | msgstr "" 61 | 62 | #: src/components/AmountWithFee.vue:11 63 | msgid "fee" 64 | msgstr "" 65 | 66 | #: src/components/PageHeader.vue:7 67 | msgid "Go back" 68 | msgstr "" 69 | 70 | #: src/components/QrScanner.vue:34 71 | msgid "Grant camera access when asked." 72 | msgstr "" 73 | 74 | #: src/components/Timer.vue:94 75 | msgid "hour" 76 | msgstr "" 77 | 78 | #: src/components/Timer.vue:95 79 | msgid "hours" 80 | msgstr "" 81 | 82 | #: src/components/AmountWithFee.vue:5 83 | msgid "Insufficient balance" 84 | msgstr "" 85 | 86 | #: src/components/LongPressButton.vue:20 87 | msgid "Keep pressing…" 88 | msgstr "" 89 | 90 | #: src/components/AccountSelector.vue:202 91 | msgid "Legacy" 92 | msgstr "" 93 | 94 | #: src/components/AccountSelector.vue:47 95 | msgid "Login to another account" 96 | msgstr "" 97 | 98 | #: src/components/Wallet.vue:26 99 | msgid "Logout" 100 | msgstr "" 101 | 102 | #: src/components/Timer.vue:92 103 | msgid "minute" 104 | msgstr "" 105 | 106 | #: src/components/Timer.vue:93 107 | msgid "minutes" 108 | msgstr "" 109 | 110 | #: src/components/LabelInput.vue:4 111 | #: src/components/LabelInput.vue:8 112 | msgid "Name your address" 113 | msgstr "" 114 | 115 | #: src/components/PaymentInfoLine.vue:88 116 | msgid "network fee" 117 | msgstr "" 118 | 119 | #: src/components/PaymentInfoLine.vue:60 120 | msgid "Nimiq provides this service free of charge." 121 | msgstr "" 122 | 123 | #: src/components/PaymentInfoLine.vue:37 124 | msgid "Order amount" 125 | msgstr "" 126 | 127 | #: src/components/Wallet.vue:23 128 | msgid "Rename" 129 | msgstr "" 130 | 131 | #: src/components/Wallet.vue:18 132 | msgid "Save Login File" 133 | msgstr "" 134 | 135 | #: src/components/Timer.vue:90 136 | msgid "second" 137 | msgstr "" 138 | 139 | #: src/components/Timer.vue:91 140 | msgid "seconds" 141 | msgstr "" 142 | 143 | #: src/components/QrScanner.vue:48 144 | msgid "the camera icon" 145 | msgstr "" 146 | 147 | #: src/components/AccountList.vue:44 148 | msgid "This address cannot be used for this operation." 149 | msgstr "" 150 | 151 | #: src/components/Timer.vue:45 152 | msgid "This offer expires in {timer}." 153 | msgstr "" 154 | 155 | #: src/components/PaymentInfoLine.vue:63 156 | msgid "Total" 157 | msgstr "" 158 | 159 | #: src/components/QrScanner.vue:20 160 | msgid "Unblock the camera for this website to scan QR codes." 161 | msgstr "" 162 | 163 | #: src/components/PaymentInfoLine.vue:41 164 | msgid "Vendor crypto discount" 165 | msgstr "" 166 | 167 | #: src/components/PaymentInfoLine.vue:40 168 | msgid "Vendor crypto markup" 169 | msgstr "" 170 | 171 | #: src/components/PaymentInfoLine.vue:297 172 | msgid "You are paying approx. {formattedRateDeviation} less than at the current market rate ({provider})." 173 | msgstr "" 174 | 175 | #: src/components/PaymentInfoLine.vue:291 176 | msgid "You are paying approx. {formattedRateDeviation} more than at the current market rate ({provider})." 177 | msgstr "" 178 | 179 | #: src/components/PaymentInfoLine.vue:283 180 | msgid "Your actual discount is approx. {formattedRateDeviation} compared to the current market rate ({provider})." 181 | msgstr "" 182 | 183 | #: src/components/QrScanner.vue:16 184 | msgid "Your device does not have an accessible camera." 185 | msgstr "" 186 | -------------------------------------------------------------------------------- /src/i18n/es.po: -------------------------------------------------------------------------------- 1 | # 2 | # Translators: 3 | # Ricardo Barquero Carranza , 2020 4 | # Daniel, 2024 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Last-Translator: Daniel, 2024\n" 9 | "Language-Team: Spanish (https://app.transifex.com/nimiq-foundation/teams/110181/es/)\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Language: es\n" 12 | "Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" 13 | 14 | #: src/components/PaymentInfoLine.vue:77 15 | msgid "{amount} suggested network fee" 16 | msgstr "{amount} cuota de red sugerida" 17 | 18 | #: src/components/AccountSelector.vue:24 19 | msgid "{type} accounts cannot be used for this operation." 20 | msgstr "cuentas tipo {type} no se pueden utilizar para esta operación." 21 | 22 | #: src/components/QrScanner.vue:11 23 | msgid "Cancel" 24 | msgstr "Cancelar" 25 | 26 | #: src/components/Wallet.vue:24 27 | msgid "Change Password" 28 | msgstr "Cambiar Contraseña" 29 | 30 | #: src/components/QrScanner.vue:24 31 | msgid "" 32 | "Click on {icon} and go to\n" 33 | "Settings > Site Settings > Camera" 34 | msgstr "" 35 | "Haga click en {icon} y visite\n" 36 | "Ajustes > Ajustes del Sitio > Cámara" 37 | 38 | #: src/components/QrScanner.vue:44 39 | msgid "Click on {icon} in the URL bar." 40 | msgstr "Haga click en {icon} en la barra del navegador." 41 | 42 | #: src/components/QrScanner.vue:39 43 | msgid "" 44 | "Click on {safari} and go to\n" 45 | "Settings for this Website > Camera" 46 | msgstr "" 47 | "Haga click en {safari} y visite\n" 48 | "Ajustes para esta Página> Cámara" 49 | 50 | #: src/components/AccountList.vue:43 51 | msgid "Contracts cannot be used for this operation." 52 | msgstr "Contratos no pueden ser utilizados para esta operación." 53 | 54 | #: src/components/Copyable.vue:5 src/components/CopyableField.vue:20 55 | msgid "Copied" 56 | msgstr "Copiado" 57 | 58 | #: src/components/Wallet.vue:21 59 | msgid "Create Backup" 60 | msgstr "Crear un respaldo" 61 | 62 | #: src/components/Timer.vue:96 63 | msgid "day" 64 | msgstr "día" 65 | 66 | #: src/components/Timer.vue:97 67 | msgid "days" 68 | msgstr "días" 69 | 70 | #: src/components/PaymentInfoLine.vue:45 71 | msgid "Effective rate" 72 | msgstr "Taza efectiva" 73 | 74 | #: src/components/AmountWithFee.vue:11 75 | msgid "fee" 76 | msgstr "cuota" 77 | 78 | #: src/components/PageHeader.vue:7 79 | msgid "Go back" 80 | msgstr "Volver" 81 | 82 | #: src/components/QrScanner.vue:34 83 | msgid "Grant camera access when asked." 84 | msgstr "De permiso a la cámara cuando se le pida" 85 | 86 | #: src/components/Timer.vue:94 87 | msgid "hour" 88 | msgstr "hora" 89 | 90 | #: src/components/Timer.vue:95 91 | msgid "hours" 92 | msgstr "horas" 93 | 94 | #: src/components/AmountWithFee.vue:5 95 | msgid "Insufficient balance" 96 | msgstr "Balance insuficiente" 97 | 98 | #: src/components/LongPressButton.vue:20 99 | msgid "Keep pressing…" 100 | msgstr "Mantenga presionado…" 101 | 102 | #: src/components/AccountSelector.vue:202 103 | msgid "Legacy" 104 | msgstr "Versión Antigua" 105 | 106 | #: src/components/AccountSelector.vue:47 107 | msgid "Login to another account" 108 | msgstr "Inicie sesión con otra cuenta" 109 | 110 | #: src/components/Wallet.vue:26 111 | msgid "Logout" 112 | msgstr "Cerrar sesión" 113 | 114 | #: src/components/Timer.vue:92 115 | msgid "minute" 116 | msgstr "minuto" 117 | 118 | #: src/components/Timer.vue:93 119 | msgid "minutes" 120 | msgstr "minutos" 121 | 122 | #: src/components/LabelInput.vue:4 src/components/LabelInput.vue:8 123 | msgid "Name your address" 124 | msgstr "De nombre a su dirección" 125 | 126 | #: src/components/PaymentInfoLine.vue:88 127 | msgid "network fee" 128 | msgstr "cuota de red" 129 | 130 | #: src/components/PaymentInfoLine.vue:60 131 | msgid "Nimiq provides this service free of charge." 132 | msgstr "Nimiq provee este servicio sin ningún costo." 133 | 134 | #: src/components/PaymentInfoLine.vue:37 135 | msgid "Order amount" 136 | msgstr "Monto de la ordén" 137 | 138 | #: src/components/Wallet.vue:23 139 | msgid "Rename" 140 | msgstr "Renombrar" 141 | 142 | #: src/components/Wallet.vue:18 143 | msgid "Save Login File" 144 | msgstr "Guardar Archivo de Sesión" 145 | 146 | #: src/components/Timer.vue:90 147 | msgid "second" 148 | msgstr "segundo" 149 | 150 | #: src/components/Timer.vue:91 151 | msgid "seconds" 152 | msgstr "segundos" 153 | 154 | #: src/components/QrScanner.vue:48 155 | msgid "the camera icon" 156 | msgstr "el icono de cámara" 157 | 158 | #: src/components/AccountList.vue:44 159 | msgid "This address cannot be used for this operation." 160 | msgstr "Esta dirección no puede ser utilizada para esta operación." 161 | 162 | #: src/components/Timer.vue:45 163 | msgid "This offer expires in {timer}." 164 | msgstr "Esta oferta expira en {timer}." 165 | 166 | #: src/components/PaymentInfoLine.vue:63 167 | msgid "Total" 168 | msgstr "Total" 169 | 170 | #: src/components/QrScanner.vue:20 171 | msgid "Unblock the camera for this website to scan QR codes." 172 | msgstr "Desbloquee la cámara para esta página para poder escanear códigos QR." 173 | 174 | #: src/components/PaymentInfoLine.vue:41 175 | msgid "Vendor crypto discount" 176 | msgstr "Descuento en criptomonedas del vendedor" 177 | 178 | #: src/components/PaymentInfoLine.vue:40 179 | msgid "Vendor crypto markup" 180 | msgstr "Margen en criptomonedas del vendedor" 181 | 182 | #: src/components/PaymentInfoLine.vue:291 183 | msgid "" 184 | "You are paying approx. {formattedRateDeviation} less than at the current " 185 | "market rate ({provider})." 186 | msgstr "" 187 | "Esta pagando approx. {formattedRateDeviation} menos que la taza actual de " 188 | "mercado ({provider})." 189 | 190 | #: src/components/PaymentInfoLine.vue:285 191 | msgid "" 192 | "You are paying approx. {formattedRateDeviation} more than at the current " 193 | "market rate ({provider})." 194 | msgstr "" 195 | "Esta pagando approx. {formattedRateDeviation} más que la taza actual de " 196 | "mercado ({provider})." 197 | 198 | #: src/components/PaymentInfoLine.vue:277 199 | msgid "" 200 | "Your actual discount is approx. {formattedRateDeviation} compared to the " 201 | "current market rate ({provider})." 202 | msgstr "" 203 | "Su descuento es approx. {formattedRateDeviation} comparado a la taza del " 204 | "mercado actual ({provider})." 205 | 206 | #: src/components/QrScanner.vue:16 207 | msgid "Your device does not have an accessible camera." 208 | msgstr "Su dispositivo no tiene una cámara accesible." 209 | -------------------------------------------------------------------------------- /src/i18n/fr.po: -------------------------------------------------------------------------------- 1 | # 2 | # Translators: 3 | # Talleyrand, 2020 4 | # Matheo , 2020 5 | # Daniel, 2024 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Last-Translator: Daniel, 2024\n" 10 | "Language-Team: French (https://app.transifex.com/nimiq-foundation/teams/110181/fr/)\n" 11 | "Content-Type: text/plain; charset=UTF-8\n" 12 | "Language: fr\n" 13 | "Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" 14 | 15 | #: src/components/PaymentInfoLine.vue:77 16 | msgid "{amount} suggested network fee" 17 | msgstr "{amount} de frais de réseau suggéré" 18 | 19 | #: src/components/AccountSelector.vue:24 20 | msgid "{type} accounts cannot be used for this operation." 21 | msgstr "Les comptes {type} ne peuvent pas être utilisés pour cette opération." 22 | 23 | #: src/components/QrScanner.vue:11 24 | msgid "Cancel" 25 | msgstr "Annuler" 26 | 27 | #: src/components/Wallet.vue:24 28 | msgid "Change Password" 29 | msgstr "Changer de Mot de passe" 30 | 31 | #: src/components/QrScanner.vue:24 32 | msgid "" 33 | "Click on {icon} and go to\n" 34 | "Settings > Site Settings > Camera" 35 | msgstr "" 36 | "Cliquez sur {icon} et allez dans\n" 37 | "Paramètres > Paramètres de site > Appareil photo" 38 | 39 | #: src/components/QrScanner.vue:44 40 | msgid "Click on {icon} in the URL bar." 41 | msgstr "Cliquez sur {icon} dans la bar d'adresse." 42 | 43 | #: src/components/QrScanner.vue:39 44 | msgid "" 45 | "Click on {safari} and go to\n" 46 | "Settings for this Website > Camera" 47 | msgstr "" 48 | "Cliquez sur {safari} et rendez-vous dans \n" 49 | "Paramètres pour ce site > Caméra" 50 | 51 | #: src/components/AccountList.vue:43 52 | msgid "Contracts cannot be used for this operation." 53 | msgstr "Les Contrats ne peuvent pas être utilisés pour cette opération." 54 | 55 | #: src/components/Copyable.vue:5 src/components/CopyableField.vue:20 56 | msgid "Copied" 57 | msgstr "Copié" 58 | 59 | #: src/components/Wallet.vue:21 60 | msgid "Create Backup" 61 | msgstr "Créer une Sauvegarde" 62 | 63 | #: src/components/Timer.vue:96 64 | msgid "day" 65 | msgstr "jour" 66 | 67 | #: src/components/Timer.vue:97 68 | msgid "days" 69 | msgstr "jours" 70 | 71 | #: src/components/PaymentInfoLine.vue:45 72 | msgid "Effective rate" 73 | msgstr "Taux effectif" 74 | 75 | #: src/components/AmountWithFee.vue:11 76 | msgid "fee" 77 | msgstr "frais" 78 | 79 | #: src/components/PageHeader.vue:7 80 | msgid "Go back" 81 | msgstr "Retour" 82 | 83 | #: src/components/QrScanner.vue:34 84 | msgid "Grant camera access when asked." 85 | msgstr "Accordez l'accès à la caméra lorsque cela vous est demandé." 86 | 87 | #: src/components/Timer.vue:94 88 | msgid "hour" 89 | msgstr "heure" 90 | 91 | #: src/components/Timer.vue:95 92 | msgid "hours" 93 | msgstr "heures" 94 | 95 | #: src/components/AmountWithFee.vue:5 96 | msgid "Insufficient balance" 97 | msgstr "Solde insuffisant" 98 | 99 | #: src/components/LongPressButton.vue:20 100 | msgid "Keep pressing…" 101 | msgstr "Continuez à appuyer…" 102 | 103 | #: src/components/AccountSelector.vue:202 104 | msgid "Legacy" 105 | msgstr "Legacy" 106 | 107 | #: src/components/AccountSelector.vue:47 108 | msgid "Login to another account" 109 | msgstr "Connexion à un autre compte" 110 | 111 | #: src/components/Wallet.vue:26 112 | msgid "Logout" 113 | msgstr "Déconnexion" 114 | 115 | #: src/components/Timer.vue:92 116 | msgid "minute" 117 | msgstr "minute" 118 | 119 | #: src/components/Timer.vue:93 120 | msgid "minutes" 121 | msgstr "minutes" 122 | 123 | #: src/components/LabelInput.vue:4 src/components/LabelInput.vue:8 124 | msgid "Name your address" 125 | msgstr "Nommez votre adresse" 126 | 127 | #: src/components/PaymentInfoLine.vue:88 128 | msgid "network fee" 129 | msgstr "frais de réseau" 130 | 131 | #: src/components/PaymentInfoLine.vue:60 132 | msgid "Nimiq provides this service free of charge." 133 | msgstr "Nimiq fournit ce service gratuitement." 134 | 135 | #: src/components/PaymentInfoLine.vue:37 136 | msgid "Order amount" 137 | msgstr "Montant de la commande" 138 | 139 | #: src/components/Wallet.vue:23 140 | msgid "Rename" 141 | msgstr "Renommer" 142 | 143 | #: src/components/Wallet.vue:18 144 | msgid "Save Login File" 145 | msgstr "Enregistrer le Fichier de Connexion" 146 | 147 | #: src/components/Timer.vue:90 148 | msgid "second" 149 | msgstr "seconde" 150 | 151 | #: src/components/Timer.vue:91 152 | msgid "seconds" 153 | msgstr "secondes" 154 | 155 | #: src/components/QrScanner.vue:48 156 | msgid "the camera icon" 157 | msgstr "l'icône de caméra" 158 | 159 | #: src/components/AccountList.vue:44 160 | msgid "This address cannot be used for this operation." 161 | msgstr "Cette adresse ne peut pas être utilisée pour cette opération." 162 | 163 | #: src/components/Timer.vue:45 164 | msgid "This offer expires in {timer}." 165 | msgstr "Cette offre expire dans {timer}." 166 | 167 | #: src/components/PaymentInfoLine.vue:63 168 | msgid "Total" 169 | msgstr "Total" 170 | 171 | #: src/components/QrScanner.vue:20 172 | msgid "Unblock the camera for this website to scan QR codes." 173 | msgstr "Débloquez la caméra pour ce site de façon à scanner les QR codes." 174 | 175 | #: src/components/PaymentInfoLine.vue:41 176 | msgid "Vendor crypto discount" 177 | msgstr "Crypto-remise" 178 | 179 | #: src/components/PaymentInfoLine.vue:40 180 | msgid "Vendor crypto markup" 181 | msgstr "Crypto-premium" 182 | 183 | #: src/components/PaymentInfoLine.vue:291 184 | msgid "" 185 | "You are paying approx. {formattedRateDeviation} less than at the current " 186 | "market rate ({provider})." 187 | msgstr "" 188 | "Vous payez environ {formattedRateDeviation} moins que le taux actuel du " 189 | "marché ({provider})." 190 | 191 | #: src/components/PaymentInfoLine.vue:285 192 | msgid "" 193 | "You are paying approx. {formattedRateDeviation} more than at the current " 194 | "market rate ({provider})." 195 | msgstr "" 196 | "Vous payez environ {formattedRateDeviation} plus que le taux actuel du " 197 | "marché ({provider})." 198 | 199 | #: src/components/PaymentInfoLine.vue:277 200 | msgid "" 201 | "Your actual discount is approx. {formattedRateDeviation} compared to the " 202 | "current market rate ({provider})." 203 | msgstr "" 204 | "Votre remise réelle est d'environ {formattedRateDeviation} par rapport au " 205 | "taux actuel du marché ({provider})." 206 | 207 | #: src/components/QrScanner.vue:16 208 | msgid "Your device does not have an accessible camera." 209 | msgstr "Votre appareil n'a pas de caméra accessible." 210 | -------------------------------------------------------------------------------- /src/i18n/nl.po: -------------------------------------------------------------------------------- 1 | # 2 | # Translators: 3 | # BlockchainShay , 2020 4 | # Stefan, 2023 5 | # Daniel, 2024 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Last-Translator: Daniel, 2024\n" 10 | "Language-Team: Dutch (https://app.transifex.com/nimiq-foundation/teams/110181/nl/)\n" 11 | "Content-Type: text/plain; charset=UTF-8\n" 12 | "Language: nl\n" 13 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 14 | 15 | #: src/components/PaymentInfoLine.vue:77 16 | msgid "{amount} suggested network fee" 17 | msgstr "{amount} voorgestelde netwerkkosten" 18 | 19 | #: src/components/AccountSelector.vue:24 20 | msgid "{type} accounts cannot be used for this operation." 21 | msgstr "{type} accounts kunnen niet worden gebruikt voor deze handeling." 22 | 23 | #: src/components/QrScanner.vue:11 24 | msgid "Cancel" 25 | msgstr "Annuleren" 26 | 27 | #: src/components/Wallet.vue:24 28 | msgid "Change Password" 29 | msgstr "Wachtwoord wijzigen" 30 | 31 | #: src/components/QrScanner.vue:24 32 | msgid "" 33 | "Click on {icon} and go to\n" 34 | "Settings > Site Settings > Camera" 35 | msgstr "" 36 | "Klik op {icon} en ga naar\n" 37 | "Instellingen > Site Instellingen > Camera" 38 | 39 | #: src/components/QrScanner.vue:44 40 | msgid "Click on {icon} in the URL bar." 41 | msgstr "Klik op {icon} in de URL bar." 42 | 43 | #: src/components/QrScanner.vue:39 44 | msgid "" 45 | "Click on {safari} and go to\n" 46 | "Settings for this Website > Camera" 47 | msgstr "" 48 | "Klik op {safari} en ga naar\n" 49 | "Instellingen voor deze Website > Camera" 50 | 51 | #: src/components/AccountList.vue:43 52 | msgid "Contracts cannot be used for this operation." 53 | msgstr "Contracten kunnen niet gebruikt worden voor deze operatie." 54 | 55 | #: src/components/Copyable.vue:5 src/components/CopyableField.vue:20 56 | msgid "Copied" 57 | msgstr "Gekopieerd" 58 | 59 | #: src/components/Wallet.vue:21 60 | msgid "Create Backup" 61 | msgstr "Maak een back-up" 62 | 63 | #: src/components/Timer.vue:96 64 | msgid "day" 65 | msgstr "dag" 66 | 67 | #: src/components/Timer.vue:97 68 | msgid "days" 69 | msgstr "dagen" 70 | 71 | #: src/components/PaymentInfoLine.vue:45 72 | msgid "Effective rate" 73 | msgstr "Effectief tarief" 74 | 75 | #: src/components/AmountWithFee.vue:11 76 | msgid "fee" 77 | msgstr "transactiekosten" 78 | 79 | #: src/components/PageHeader.vue:7 80 | msgid "Go back" 81 | msgstr "Ga terug" 82 | 83 | #: src/components/QrScanner.vue:34 84 | msgid "Grant camera access when asked." 85 | msgstr "Verleen cameratoegang wanneer daarom wordt gevraagd." 86 | 87 | #: src/components/Timer.vue:94 88 | msgid "hour" 89 | msgstr "uur" 90 | 91 | #: src/components/Timer.vue:95 92 | msgid "hours" 93 | msgstr "uren" 94 | 95 | #: src/components/AmountWithFee.vue:5 96 | msgid "Insufficient balance" 97 | msgstr "Onvoldoende salso" 98 | 99 | #: src/components/LongPressButton.vue:20 100 | msgid "Keep pressing…" 101 | msgstr "Ingedrukt houden…" 102 | 103 | #: src/components/AccountSelector.vue:202 104 | msgid "Legacy" 105 | msgstr "Legacy" 106 | 107 | #: src/components/AccountSelector.vue:47 108 | msgid "Login to another account" 109 | msgstr "Log in op een ander account" 110 | 111 | #: src/components/Wallet.vue:26 112 | msgid "Logout" 113 | msgstr "Uitloggen" 114 | 115 | #: src/components/Timer.vue:92 116 | msgid "minute" 117 | msgstr "minuut" 118 | 119 | #: src/components/Timer.vue:93 120 | msgid "minutes" 121 | msgstr "minuten" 122 | 123 | #: src/components/LabelInput.vue:4 src/components/LabelInput.vue:8 124 | msgid "Name your address" 125 | msgstr "Geef adres een naam" 126 | 127 | #: src/components/PaymentInfoLine.vue:88 128 | msgid "network fee" 129 | msgstr "netwerkkosten" 130 | 131 | #: src/components/PaymentInfoLine.vue:60 132 | msgid "Nimiq provides this service free of charge." 133 | msgstr "Nimiq biedt deze service gratis aan." 134 | 135 | #: src/components/PaymentInfoLine.vue:37 136 | msgid "Order amount" 137 | msgstr "Orderbedrag" 138 | 139 | #: src/components/Wallet.vue:23 140 | msgid "Rename" 141 | msgstr "Hernoemen" 142 | 143 | #: src/components/Wallet.vue:18 144 | msgid "Save Login File" 145 | msgstr "Login File opslaan" 146 | 147 | #: src/components/Timer.vue:90 148 | msgid "second" 149 | msgstr "seconde" 150 | 151 | #: src/components/Timer.vue:91 152 | msgid "seconds" 153 | msgstr "seconden" 154 | 155 | #: src/components/QrScanner.vue:48 156 | msgid "the camera icon" 157 | msgstr "de camera icon" 158 | 159 | #: src/components/AccountList.vue:44 160 | msgid "This address cannot be used for this operation." 161 | msgstr "Dit adres kan niet worden gebruikt voor deze handeling." 162 | 163 | #: src/components/Timer.vue:45 164 | msgid "This offer expires in {timer}." 165 | msgstr "Deze aanbieding vervalt over {timer}." 166 | 167 | #: src/components/PaymentInfoLine.vue:63 168 | msgid "Total" 169 | msgstr "Totaal" 170 | 171 | #: src/components/QrScanner.vue:20 172 | msgid "Unblock the camera for this website to scan QR codes." 173 | msgstr "Deblokkeer de camera zodat deze website QR-codes kan scannen." 174 | 175 | #: src/components/PaymentInfoLine.vue:41 176 | msgid "Vendor crypto discount" 177 | msgstr "Crypto leverancier korting" 178 | 179 | #: src/components/PaymentInfoLine.vue:40 180 | msgid "Vendor crypto markup" 181 | msgstr "Markering van crypto-leveranciers" 182 | 183 | #: src/components/PaymentInfoLine.vue:291 184 | msgid "" 185 | "You are paying approx. {formattedRateDeviation} less than at the current " 186 | "market rate ({provider})." 187 | msgstr "" 188 | "Je betaalt ongeveer {formattedRateDeviation} lager dan tegen de huidige " 189 | "marktkoers ({provider})." 190 | 191 | #: src/components/PaymentInfoLine.vue:285 192 | msgid "" 193 | "You are paying approx. {formattedRateDeviation} more than at the current " 194 | "market rate ({provider})." 195 | msgstr "" 196 | "Je betaalt ongeveer {formattedRateDeviation} meer dan tegen de huidige " 197 | "marktkoers ({provider})." 198 | 199 | #: src/components/PaymentInfoLine.vue:277 200 | msgid "" 201 | "Your actual discount is approx. {formattedRateDeviation} compared to the " 202 | "current market rate ({provider})." 203 | msgstr "" 204 | "Je daadwerkelijke korting is ca. {formattedRateDeviation} in vergelijking " 205 | "met de huidige marktkoers ({provider})." 206 | 207 | #: src/components/QrScanner.vue:16 208 | msgid "Your device does not have an accessible camera." 209 | msgstr "Uw apparaat heeft geen toegankelijke camera." 210 | -------------------------------------------------------------------------------- /src/i18n/pt.po: -------------------------------------------------------------------------------- 1 | # 2 | # Translators: 3 | # Inês Marques Gomes, 2024 4 | # Daniel, 2024 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Last-Translator: Daniel, 2024\n" 9 | "Language-Team: Portuguese (https://app.transifex.com/nimiq-foundation/teams/110181/pt/)\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Language: pt\n" 12 | "Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" 13 | 14 | #: src/components/PaymentInfoLine.vue:77 15 | msgid "{amount} suggested network fee" 16 | msgstr "{amount} taxa de rede sugerida" 17 | 18 | #: src/components/AccountSelector.vue:24 19 | msgid "{type} accounts cannot be used for this operation." 20 | msgstr "Contas {type} não podem ser usadas para esta operação." 21 | 22 | #: src/components/QrScanner.vue:11 23 | msgid "Cancel" 24 | msgstr "Cancelar" 25 | 26 | #: src/components/Wallet.vue:24 27 | msgid "Change Password" 28 | msgstr "Mudar Palavra Passe" 29 | 30 | #: src/components/QrScanner.vue:24 31 | msgid "" 32 | "Click on {icon} and go to\n" 33 | "Settings > Site Settings > Camera" 34 | msgstr "" 35 | "Clica na {icon} e vai para\n" 36 | "Definições > Definições do site > Câmara" 37 | 38 | #: src/components/QrScanner.vue:44 39 | msgid "Click on {icon} in the URL bar." 40 | msgstr "Clica na {icon} na barra de URL." 41 | 42 | #: src/components/QrScanner.vue:39 43 | msgid "" 44 | "Click on {safari} and go to\n" 45 | "Settings for this Website > Camera" 46 | msgstr "" 47 | "Clica na {safari} e vai para\n" 48 | "Definições para este site > Câmara" 49 | 50 | #: src/components/AccountList.vue:43 51 | msgid "Contracts cannot be used for this operation." 52 | msgstr "Contratos não podem ser usados para esta operação." 53 | 54 | #: src/components/Copyable.vue:5 src/components/CopyableField.vue:20 55 | msgid "Copied" 56 | msgstr "Copiado" 57 | 58 | #: src/components/Wallet.vue:21 59 | msgid "Create Backup" 60 | msgstr "Criar Backup" 61 | 62 | #: src/components/Timer.vue:96 63 | msgid "day" 64 | msgstr "dia" 65 | 66 | #: src/components/Timer.vue:97 67 | msgid "days" 68 | msgstr "dias" 69 | 70 | #: src/components/PaymentInfoLine.vue:45 71 | msgid "Effective rate" 72 | msgstr "Taxa efetiva" 73 | 74 | #: src/components/AmountWithFee.vue:11 75 | msgid "fee" 76 | msgstr "taxa" 77 | 78 | #: src/components/PageHeader.vue:7 79 | msgid "Go back" 80 | msgstr "Voltar" 81 | 82 | #: src/components/QrScanner.vue:34 83 | msgid "Grant camera access when asked." 84 | msgstr "Concede acesso à câmara quando solicitado." 85 | 86 | #: src/components/Timer.vue:94 87 | msgid "hour" 88 | msgstr "hora" 89 | 90 | #: src/components/Timer.vue:95 91 | msgid "hours" 92 | msgstr "horas" 93 | 94 | #: src/components/AmountWithFee.vue:5 95 | msgid "Insufficient balance" 96 | msgstr "Saldo insuficiente" 97 | 98 | #: src/components/LongPressButton.vue:20 99 | msgid "Keep pressing…" 100 | msgstr "Continua a pressionar…" 101 | 102 | #: src/components/AccountSelector.vue:202 103 | msgid "Legacy" 104 | msgstr "Legacy" 105 | 106 | #: src/components/AccountSelector.vue:47 107 | msgid "Login to another account" 108 | msgstr "Inicia sessão noutra conta" 109 | 110 | #: src/components/Wallet.vue:26 111 | msgid "Logout" 112 | msgstr "Encerrar sessão" 113 | 114 | #: src/components/Timer.vue:92 115 | msgid "minute" 116 | msgstr "minuto" 117 | 118 | #: src/components/Timer.vue:93 119 | msgid "minutes" 120 | msgstr "minutos" 121 | 122 | #: src/components/LabelInput.vue:4 src/components/LabelInput.vue:8 123 | msgid "Name your address" 124 | msgstr "Dá um nome ao teu endereço" 125 | 126 | #: src/components/PaymentInfoLine.vue:88 127 | msgid "network fee" 128 | msgstr "taxa de rede" 129 | 130 | #: src/components/PaymentInfoLine.vue:60 131 | msgid "Nimiq provides this service free of charge." 132 | msgstr "A Nimiq oferece este serviço." 133 | 134 | #: src/components/PaymentInfoLine.vue:37 135 | msgid "Order amount" 136 | msgstr "Valor do pedido" 137 | 138 | #: src/components/Wallet.vue:23 139 | msgid "Rename" 140 | msgstr "Mudar de nome" 141 | 142 | #: src/components/Wallet.vue:18 143 | msgid "Save Login File" 144 | msgstr "Salvar Ficheiro de Login" 145 | 146 | #: src/components/Timer.vue:90 147 | msgid "second" 148 | msgstr "segundo" 149 | 150 | #: src/components/Timer.vue:91 151 | msgid "seconds" 152 | msgstr "segundos" 153 | 154 | #: src/components/QrScanner.vue:48 155 | msgid "the camera icon" 156 | msgstr "ícone da câmara" 157 | 158 | #: src/components/AccountList.vue:44 159 | msgid "This address cannot be used for this operation." 160 | msgstr "Este endereço não pode ser usado para esta operação." 161 | 162 | #: src/components/Timer.vue:45 163 | msgid "This offer expires in {timer}." 164 | msgstr "Esta oferta expira em   {timer}" 165 | 166 | #: src/components/PaymentInfoLine.vue:63 167 | msgid "Total" 168 | msgstr "Total" 169 | 170 | #: src/components/QrScanner.vue:20 171 | msgid "Unblock the camera for this website to scan QR codes." 172 | msgstr "Desbloquear a câmara para o site digitalizar os códigos QR." 173 | 174 | #: src/components/PaymentInfoLine.vue:41 175 | msgid "Vendor crypto discount" 176 | msgstr "Desconto do fornecedor da cripto" 177 | 178 | #: src/components/PaymentInfoLine.vue:40 179 | msgid "Vendor crypto markup" 180 | msgstr "Acerto de preço do fornecedor da criptomoeda" 181 | 182 | #: src/components/PaymentInfoLine.vue:291 183 | msgid "" 184 | "You are paying approx. {formattedRateDeviation} less than at the current " 185 | "market rate ({provider})." 186 | msgstr "" 187 | "Estás a pagar aproximadamente {formattedRateDeviation} a menos que a taxa do" 188 | " mercado atual ({provider})." 189 | 190 | #: src/components/PaymentInfoLine.vue:285 191 | msgid "" 192 | "You are paying approx. {formattedRateDeviation} more than at the current " 193 | "market rate ({provider})." 194 | msgstr "" 195 | "Estás a pagar aproximadamente {formattedRateDeviation} a mais que a taxa " 196 | "atual do mercado ({provider})." 197 | 198 | #: src/components/PaymentInfoLine.vue:277 199 | msgid "" 200 | "Your actual discount is approx. {formattedRateDeviation} compared to the " 201 | "current market rate ({provider})." 202 | msgstr "" 203 | "O teu desconto é aproximadamente {formattedRateDeviation} comparado com a " 204 | "taxa atual do mercado ({provider})." 205 | 206 | #: src/components/QrScanner.vue:16 207 | msgid "Your device does not have an accessible camera." 208 | msgstr "O teu dispositivo não tem uma câmara acessível." 209 | -------------------------------------------------------------------------------- /src/i18n/ru.po: -------------------------------------------------------------------------------- 1 | # 2 | # Translators: 3 | # Vad , 2020 4 | # Пётр Павлович, 2020 5 | # Alexander Ivanov , 2023 6 | # Daniel, 2024 7 | # 8 | msgid "" 9 | msgstr "" 10 | "Last-Translator: Daniel, 2024\n" 11 | "Language-Team: Russian (https://app.transifex.com/nimiq-foundation/teams/110181/ru/)\n" 12 | "Content-Type: text/plain; charset=UTF-8\n" 13 | "Language: ru\n" 14 | "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" 15 | 16 | #: src/components/PaymentInfoLine.vue:77 17 | msgid "{amount} suggested network fee" 18 | msgstr "{amount} предлагаемая комиссия сети" 19 | 20 | #: src/components/AccountSelector.vue:24 21 | msgid "{type} accounts cannot be used for this operation." 22 | msgstr "Аккаунты типа {type} не могут быть использованы для этой операции." 23 | 24 | #: src/components/QrScanner.vue:11 25 | msgid "Cancel" 26 | msgstr "Отмена" 27 | 28 | #: src/components/Wallet.vue:24 29 | msgid "Change Password" 30 | msgstr "Сменить пароль" 31 | 32 | #: src/components/QrScanner.vue:24 33 | msgid "" 34 | "Click on {icon} and go to\n" 35 | "Settings > Site Settings > Camera" 36 | msgstr "" 37 | "Нажмите на {icon} и перейдите в\n" 38 | "Настройки > Настройки сайта > Камера" 39 | 40 | #: src/components/QrScanner.vue:44 41 | msgid "Click on {icon} in the URL bar." 42 | msgstr "Нажмите на {icon} в адресной строке." 43 | 44 | #: src/components/QrScanner.vue:39 45 | msgid "" 46 | "Click on {safari} and go to\n" 47 | "Settings for this Website > Camera" 48 | msgstr "" 49 | "Нажмите на {safari} и перейдите в\n" 50 | "Настройки для данного Веб-сайта > Камера" 51 | 52 | #: src/components/AccountList.vue:43 53 | msgid "Contracts cannot be used for this operation." 54 | msgstr "Контракты не могут быть использованы для этой операции." 55 | 56 | #: src/components/Copyable.vue:5 src/components/CopyableField.vue:20 57 | msgid "Copied" 58 | msgstr "Скопировано" 59 | 60 | #: src/components/Wallet.vue:21 61 | msgid "Create Backup" 62 | msgstr "Создать резервную копию" 63 | 64 | #: src/components/Timer.vue:96 65 | msgid "day" 66 | msgstr "день" 67 | 68 | #: src/components/Timer.vue:97 69 | msgid "days" 70 | msgstr "дней" 71 | 72 | #: src/components/PaymentInfoLine.vue:45 73 | msgid "Effective rate" 74 | msgstr "Настоящий курс" 75 | 76 | #: src/components/AmountWithFee.vue:11 77 | msgid "fee" 78 | msgstr "комиссия" 79 | 80 | #: src/components/PageHeader.vue:7 81 | msgid "Go back" 82 | msgstr "Назад" 83 | 84 | #: src/components/QrScanner.vue:34 85 | msgid "Grant camera access when asked." 86 | msgstr "Предоставьте доступ к камере, когда вас об этом попросят." 87 | 88 | #: src/components/Timer.vue:94 89 | msgid "hour" 90 | msgstr "час" 91 | 92 | #: src/components/Timer.vue:95 93 | msgid "hours" 94 | msgstr "часов" 95 | 96 | #: src/components/AmountWithFee.vue:5 97 | msgid "Insufficient balance" 98 | msgstr "Недостаточный баланс" 99 | 100 | #: src/components/LongPressButton.vue:20 101 | msgid "Keep pressing…" 102 | msgstr "Продолжайте нажимать…" 103 | 104 | #: src/components/AccountSelector.vue:202 105 | msgid "Legacy" 106 | msgstr "\"старый\"" 107 | 108 | #: src/components/AccountSelector.vue:47 109 | msgid "Login to another account" 110 | msgstr "Вход в другой аккаунт" 111 | 112 | #: src/components/Wallet.vue:26 113 | msgid "Logout" 114 | msgstr "Выйти" 115 | 116 | #: src/components/Timer.vue:92 117 | msgid "minute" 118 | msgstr "минута" 119 | 120 | #: src/components/Timer.vue:93 121 | msgid "minutes" 122 | msgstr "минут" 123 | 124 | #: src/components/LabelInput.vue:4 src/components/LabelInput.vue:8 125 | msgid "Name your address" 126 | msgstr "Как вы назовёте свой адрес?" 127 | 128 | #: src/components/PaymentInfoLine.vue:88 129 | msgid "network fee" 130 | msgstr "комиссия сети" 131 | 132 | #: src/components/PaymentInfoLine.vue:60 133 | msgid "Nimiq provides this service free of charge." 134 | msgstr "Nimiq предоставляет эту услугу бесплатно." 135 | 136 | #: src/components/PaymentInfoLine.vue:37 137 | msgid "Order amount" 138 | msgstr "Сумма заказа" 139 | 140 | #: src/components/Wallet.vue:23 141 | msgid "Rename" 142 | msgstr "Переименовать" 143 | 144 | #: src/components/Wallet.vue:18 145 | msgid "Save Login File" 146 | msgstr "Сохранить Файл Авторизации" 147 | 148 | #: src/components/Timer.vue:90 149 | msgid "second" 150 | msgstr "секунда" 151 | 152 | #: src/components/Timer.vue:91 153 | msgid "seconds" 154 | msgstr "секунд" 155 | 156 | #: src/components/QrScanner.vue:48 157 | msgid "the camera icon" 158 | msgstr "значок камеры" 159 | 160 | #: src/components/AccountList.vue:44 161 | msgid "This address cannot be used for this operation." 162 | msgstr "Этот адрес не может быть использован для данной операции." 163 | 164 | #: src/components/Timer.vue:45 165 | msgid "This offer expires in {timer}." 166 | msgstr "Срок действия этого предложения истекает через {timer}." 167 | 168 | #: src/components/PaymentInfoLine.vue:63 169 | msgid "Total" 170 | msgstr "Итого" 171 | 172 | #: src/components/QrScanner.vue:20 173 | msgid "Unblock the camera for this website to scan QR codes." 174 | msgstr "Разблокируйте камеру для этого сайта, чтобы сканировать QR-коды." 175 | 176 | #: src/components/PaymentInfoLine.vue:41 177 | msgid "Vendor crypto discount" 178 | msgstr "Скидка вендора криптовалюты" 179 | 180 | #: src/components/PaymentInfoLine.vue:40 181 | msgid "Vendor crypto markup" 182 | msgstr "Наценка вендора криптовалюты" 183 | 184 | #: src/components/PaymentInfoLine.vue:291 185 | msgid "" 186 | "You are paying approx. {formattedRateDeviation} less than at the current " 187 | "market rate ({provider})." 188 | msgstr "" 189 | "Вы платите примерно на {formattedRateDeviation} меньше чем по рыночному " 190 | "курсу ({provider})." 191 | 192 | #: src/components/PaymentInfoLine.vue:285 193 | msgid "" 194 | "You are paying approx. {formattedRateDeviation} more than at the current " 195 | "market rate ({provider})." 196 | msgstr "" 197 | "Вы платите примерно на {formattedRateDeviation} больше чем по рыночному " 198 | "курсу ({provider})." 199 | 200 | #: src/components/PaymentInfoLine.vue:277 201 | msgid "" 202 | "Your actual discount is approx. {formattedRateDeviation} compared to the " 203 | "current market rate ({provider})." 204 | msgstr "" 205 | "Ваш фактический дисконт составляет приблизительно {formattedRateDeviation} " 206 | "по сравнению с рыночным курсом ({provider})." 207 | 208 | #: src/components/QrScanner.vue:16 209 | msgid "Your device does not have an accessible camera." 210 | msgstr "Камера вашего устройства недоступна." 211 | -------------------------------------------------------------------------------- /src/i18n/uk.po: -------------------------------------------------------------------------------- 1 | # 2 | # Translators: 3 | # Oleksandr Turchyn , 2020 4 | # Petro M , 2020 5 | # Daniel, 2024 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Last-Translator: Daniel, 2024\n" 10 | "Language-Team: Ukrainian (https://app.transifex.com/nimiq-foundation/teams/110181/uk/)\n" 11 | "Content-Type: text/plain; charset=UTF-8\n" 12 | "Language: uk\n" 13 | "Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n" 14 | 15 | #: src/components/PaymentInfoLine.vue:77 16 | msgid "{amount} suggested network fee" 17 | msgstr "{amount} комісія запропонована мережею" 18 | 19 | #: src/components/AccountSelector.vue:24 20 | msgid "{type} accounts cannot be used for this operation." 21 | msgstr "{type} рахунок не може бути використаний для цієї операції." 22 | 23 | #: src/components/QrScanner.vue:11 24 | msgid "Cancel" 25 | msgstr "Скасувати" 26 | 27 | #: src/components/Wallet.vue:24 28 | msgid "Change Password" 29 | msgstr "Змінити пароль" 30 | 31 | #: src/components/QrScanner.vue:24 32 | msgid "" 33 | "Click on {icon} and go to\n" 34 | "Settings > Site Settings > Camera" 35 | msgstr "" 36 | "Натисніть на {icon} і перейдіть до\n" 37 | "Налаштування > Налаштування сайту > Камера" 38 | 39 | #: src/components/QrScanner.vue:44 40 | msgid "Click on {icon} in the URL bar." 41 | msgstr "Натисніть на {icon} у рядку URL." 42 | 43 | #: src/components/QrScanner.vue:39 44 | msgid "" 45 | "Click on {safari} and go to\n" 46 | "Settings for this Website > Camera" 47 | msgstr "" 48 | "Натисніть на {safari} і перейдіть до\n" 49 | "Налаштування для цього веб-сайту > Камера" 50 | 51 | #: src/components/AccountList.vue:43 52 | msgid "Contracts cannot be used for this operation." 53 | msgstr "Контракти не можуть бути використані для цієї операції." 54 | 55 | #: src/components/Copyable.vue:5 src/components/CopyableField.vue:20 56 | msgid "Copied" 57 | msgstr "Скопійовано" 58 | 59 | #: src/components/Wallet.vue:21 60 | msgid "Create Backup" 61 | msgstr "Створити резервну копію" 62 | 63 | #: src/components/Timer.vue:96 64 | msgid "day" 65 | msgstr "день" 66 | 67 | #: src/components/Timer.vue:97 68 | msgid "days" 69 | msgstr "днів" 70 | 71 | #: src/components/PaymentInfoLine.vue:45 72 | msgid "Effective rate" 73 | msgstr "Фактична ставка" 74 | 75 | #: src/components/AmountWithFee.vue:11 76 | msgid "fee" 77 | msgstr "комісія" 78 | 79 | #: src/components/PageHeader.vue:7 80 | msgid "Go back" 81 | msgstr "Назад" 82 | 83 | #: src/components/QrScanner.vue:34 84 | msgid "Grant camera access when asked." 85 | msgstr "Надайте доступ до камери, коли попросять." 86 | 87 | #: src/components/Timer.vue:94 88 | msgid "hour" 89 | msgstr "година" 90 | 91 | #: src/components/Timer.vue:95 92 | msgid "hours" 93 | msgstr "годин" 94 | 95 | #: src/components/AmountWithFee.vue:5 96 | msgid "Insufficient balance" 97 | msgstr "Недостатній баланс" 98 | 99 | #: src/components/LongPressButton.vue:20 100 | msgid "Keep pressing…" 101 | msgstr "Продовжуйте натискати…" 102 | 103 | #: src/components/AccountSelector.vue:202 104 | msgid "Legacy" 105 | msgstr "Старий формат" 106 | 107 | #: src/components/AccountSelector.vue:47 108 | msgid "Login to another account" 109 | msgstr "Увійти на інший рахунок" 110 | 111 | #: src/components/Wallet.vue:26 112 | msgid "Logout" 113 | msgstr "Вийти" 114 | 115 | #: src/components/Timer.vue:92 116 | msgid "minute" 117 | msgstr "хвилина" 118 | 119 | #: src/components/Timer.vue:93 120 | msgid "minutes" 121 | msgstr "хвилин" 122 | 123 | #: src/components/LabelInput.vue:4 src/components/LabelInput.vue:8 124 | msgid "Name your address" 125 | msgstr "Назвіть вашу адресу" 126 | 127 | #: src/components/PaymentInfoLine.vue:88 128 | msgid "network fee" 129 | msgstr "комісія мережі" 130 | 131 | #: src/components/PaymentInfoLine.vue:60 132 | msgid "Nimiq provides this service free of charge." 133 | msgstr "Nimiq надає цю послугу безкоштовно." 134 | 135 | #: src/components/PaymentInfoLine.vue:37 136 | msgid "Order amount" 137 | msgstr "Сума замовлення" 138 | 139 | #: src/components/Wallet.vue:23 140 | msgid "Rename" 141 | msgstr "Перейменувати" 142 | 143 | #: src/components/Wallet.vue:18 144 | msgid "Save Login File" 145 | msgstr "Зберегти файл-ключ" 146 | 147 | #: src/components/Timer.vue:90 148 | msgid "second" 149 | msgstr "секунда" 150 | 151 | #: src/components/Timer.vue:91 152 | msgid "seconds" 153 | msgstr "секунд" 154 | 155 | #: src/components/QrScanner.vue:48 156 | msgid "the camera icon" 157 | msgstr "значок камери" 158 | 159 | #: src/components/AccountList.vue:44 160 | msgid "This address cannot be used for this operation." 161 | msgstr "Ця адреса не може бути використана для цієї операції." 162 | 163 | #: src/components/Timer.vue:45 164 | msgid "This offer expires in {timer}." 165 | msgstr "Термін дії цієї пропозиції закінчується через {timer}." 166 | 167 | #: src/components/PaymentInfoLine.vue:63 168 | msgid "Total" 169 | msgstr "Загалом" 170 | 171 | #: src/components/QrScanner.vue:20 172 | msgid "Unblock the camera for this website to scan QR codes." 173 | msgstr "Розблокуйте камеру для цього веб-сайту, щоб сканувати QR-коди." 174 | 175 | #: src/components/PaymentInfoLine.vue:41 176 | msgid "Vendor crypto discount" 177 | msgstr "Знижка постачальника" 178 | 179 | #: src/components/PaymentInfoLine.vue:40 180 | msgid "Vendor crypto markup" 181 | msgstr "Націнка постачальника" 182 | 183 | #: src/components/PaymentInfoLine.vue:291 184 | msgid "" 185 | "You are paying approx. {formattedRateDeviation} less than at the current " 186 | "market rate ({provider})." 187 | msgstr "" 188 | "Ви платите приблизно на {formattedRateDeviation} менше, ніж за поточним " 189 | "ринковим курсом ({provider})." 190 | 191 | #: src/components/PaymentInfoLine.vue:285 192 | msgid "" 193 | "You are paying approx. {formattedRateDeviation} more than at the current " 194 | "market rate ({provider})." 195 | msgstr "" 196 | "Ви платите приблизно на {formattedRateDeviation} більше, ніж за поточним " 197 | "ринковим курсом ({provider})." 198 | 199 | #: src/components/PaymentInfoLine.vue:277 200 | msgid "" 201 | "Your actual discount is approx. {formattedRateDeviation} compared to the " 202 | "current market rate ({provider})." 203 | msgstr "" 204 | "Ваша фактична знижка становить приблизно {formattedRateDeviation}, якщо " 205 | "порівняти з поточним ринковим курсом ({provider})." 206 | 207 | #: src/components/QrScanner.vue:16 208 | msgid "Your device does not have an accessible camera." 209 | msgstr "Ваш пристрій не має доступної камери." 210 | -------------------------------------------------------------------------------- /src/i18n/zh.po: -------------------------------------------------------------------------------- 1 | # 2 | # Translators: 3 | # Sven , 2021 4 | # Sam, 2023 5 | # Daniel, 2024 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Last-Translator: Daniel, 2024\n" 10 | "Language-Team: Chinese (https://app.transifex.com/nimiq-foundation/teams/110181/zh/)\n" 11 | "Content-Type: text/plain; charset=UTF-8\n" 12 | "Language: zh\n" 13 | "Plural-Forms: nplurals=1; plural=0;\n" 14 | 15 | #: src/components/PaymentInfoLine.vue:77 16 | msgid "{amount} suggested network fee" 17 | msgstr "建议的网络费用为{amount}" 18 | 19 | #: src/components/AccountSelector.vue:24 20 | msgid "{type} accounts cannot be used for this operation." 21 | msgstr "{type}个帐户不适用于此操作" 22 | 23 | #: src/components/QrScanner.vue:11 24 | msgid "Cancel" 25 | msgstr "取消" 26 | 27 | #: src/components/Wallet.vue:24 28 | msgid "Change Password" 29 | msgstr "更改密码" 30 | 31 | #: src/components/QrScanner.vue:24 32 | msgid "" 33 | "Click on {icon} and go to\n" 34 | "Settings > Site Settings > Camera" 35 | msgstr "" 36 | "点击 {icon},进入\n" 37 | "设置>网站设置>相机" 38 | 39 | #: src/components/QrScanner.vue:44 40 | msgid "Click on {icon} in the URL bar." 41 | msgstr "点击网址栏中的{icon}" 42 | 43 | #: src/components/QrScanner.vue:39 44 | msgid "" 45 | "Click on {safari} and go to\n" 46 | "Settings for this Website > Camera" 47 | msgstr "" 48 | "点击{safari}并转到\n" 49 | "此网站的设置>相机" 50 | 51 | #: src/components/AccountList.vue:43 52 | msgid "Contracts cannot be used for this operation." 53 | msgstr "合同不适用于此操作" 54 | 55 | #: src/components/Copyable.vue:5 src/components/CopyableField.vue:20 56 | msgid "Copied" 57 | msgstr "已复制" 58 | 59 | #: src/components/Wallet.vue:21 60 | msgid "Create Backup" 61 | msgstr "创建备份" 62 | 63 | #: src/components/Timer.vue:96 64 | msgid "day" 65 | msgstr "天" 66 | 67 | #: src/components/Timer.vue:97 68 | msgid "days" 69 | msgstr "天" 70 | 71 | #: src/components/PaymentInfoLine.vue:45 72 | msgid "Effective rate" 73 | msgstr "有效汇率" 74 | 75 | #: src/components/AmountWithFee.vue:11 76 | msgid "fee" 77 | msgstr "费用" 78 | 79 | #: src/components/PageHeader.vue:7 80 | msgid "Go back" 81 | msgstr "返回" 82 | 83 | #: src/components/QrScanner.vue:34 84 | msgid "Grant camera access when asked." 85 | msgstr "请在询问时,授予摄像机访问权限" 86 | 87 | #: src/components/Timer.vue:94 88 | msgid "hour" 89 | msgstr "时" 90 | 91 | #: src/components/Timer.vue:95 92 | msgid "hours" 93 | msgstr "时" 94 | 95 | #: src/components/AmountWithFee.vue:5 96 | msgid "Insufficient balance" 97 | msgstr "余额不足" 98 | 99 | #: src/components/LongPressButton.vue:20 100 | msgid "Keep pressing…" 101 | msgstr "请持续点击。。。" 102 | 103 | #: src/components/AccountSelector.vue:202 104 | msgid "Legacy" 105 | msgstr "传统" 106 | 107 | #: src/components/AccountSelector.vue:47 108 | msgid "Login to another account" 109 | msgstr "登录另一个帐户" 110 | 111 | #: src/components/Wallet.vue:26 112 | msgid "Logout" 113 | msgstr "登出" 114 | 115 | #: src/components/Timer.vue:92 116 | msgid "minute" 117 | msgstr "分" 118 | 119 | #: src/components/Timer.vue:93 120 | msgid "minutes" 121 | msgstr "分" 122 | 123 | #: src/components/LabelInput.vue:4 src/components/LabelInput.vue:8 124 | msgid "Name your address" 125 | msgstr "命名你的地址" 126 | 127 | #: src/components/PaymentInfoLine.vue:88 128 | msgid "network fee" 129 | msgstr "网络费用" 130 | 131 | #: src/components/PaymentInfoLine.vue:60 132 | msgid "Nimiq provides this service free of charge." 133 | msgstr "Nimiq免费提供此服务" 134 | 135 | #: src/components/PaymentInfoLine.vue:37 136 | msgid "Order amount" 137 | msgstr "订单金额" 138 | 139 | #: src/components/Wallet.vue:23 140 | msgid "Rename" 141 | msgstr "重新命名" 142 | 143 | #: src/components/Wallet.vue:18 144 | msgid "Save Login File" 145 | msgstr "储存登录文件" 146 | 147 | #: src/components/Timer.vue:90 148 | msgid "second" 149 | msgstr "秒" 150 | 151 | #: src/components/Timer.vue:91 152 | msgid "seconds" 153 | msgstr "秒" 154 | 155 | #: src/components/QrScanner.vue:48 156 | msgid "the camera icon" 157 | msgstr "相机图标" 158 | 159 | #: src/components/AccountList.vue:44 160 | msgid "This address cannot be used for this operation." 161 | msgstr "该地址不适用此操作" 162 | 163 | #: src/components/Timer.vue:45 164 | msgid "This offer expires in {timer}." 165 | msgstr "该价格将在{timer}后过期" 166 | 167 | #: src/components/PaymentInfoLine.vue:63 168 | msgid "Total" 169 | msgstr "总共" 170 | 171 | #: src/components/QrScanner.vue:20 172 | msgid "Unblock the camera for this website to scan QR codes." 173 | msgstr "打开此网站相机的使用权限以扫描QR码" 174 | 175 | #: src/components/PaymentInfoLine.vue:41 176 | msgid "Vendor crypto discount" 177 | msgstr "供应商的加密货币折扣" 178 | 179 | #: src/components/PaymentInfoLine.vue:40 180 | msgid "Vendor crypto markup" 181 | msgstr "供应商加密货币标记" 182 | 183 | #: src/components/PaymentInfoLine.vue:291 184 | msgid "" 185 | "You are paying approx. {formattedRateDeviation} less than at the current " 186 | "market rate ({provider})." 187 | msgstr "你正在支付约{formattedRateDeviation}低于当前市场的价格({provider})" 188 | 189 | #: src/components/PaymentInfoLine.vue:285 190 | msgid "" 191 | "You are paying approx. {formattedRateDeviation} more than at the current " 192 | "market rate ({provider})." 193 | msgstr "你正在支付约{formattedRateDeviation}高于当前市场的价格({provider})" 194 | 195 | #: src/components/PaymentInfoLine.vue:277 196 | msgid "" 197 | "Your actual discount is approx. {formattedRateDeviation} compared to the " 198 | "current market rate ({provider})." 199 | msgstr "你的实际折扣约为{formattedRateDeviation}与当前市场价格({provider})的比较" 200 | 201 | #: src/components/QrScanner.vue:16 202 | msgid "Your device does not have an accessible camera." 203 | msgstr "你的设备没有可访问的相机" 204 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | // Components 2 | export { default as Account } from './components/Account.vue'; 3 | export { default as AccountDetails } from './components/AccountDetails.vue'; 4 | export { default as AccountList } from './components/AccountList.vue'; 5 | export { default as AccountRing } from './components/AccountRing.vue'; 6 | export { default as AccountSelector } from './components/AccountSelector.vue'; 7 | export { default as AddressDisplay } from './components/AddressDisplay.vue'; 8 | export { default as AddressInput } from './components/AddressInput.vue'; 9 | export { default as Amount } from './components/Amount.vue'; 10 | export { default as AmountInput } from './components/AmountInput.vue'; 11 | export { default as AmountWithFee } from './components/AmountWithFee.vue'; 12 | export { default as BottomOverlay } from './components/BottomOverlay.vue'; 13 | export { default as Carousel } from './components/Carousel.vue'; 14 | export { default as CircleSpinner } from './components/CircleSpinner.vue'; 15 | export { default as CloseButton } from './components/CloseButton.vue'; 16 | export { default as Copyable } from './components/Copyable.vue'; 17 | export { default as CopyableField } from './components/CopyableField.vue'; 18 | export { default as FiatAmount } from './components/FiatAmount.vue'; 19 | export { default as Identicon } from './components/Identicon.vue'; 20 | export { default as LabelInput } from './components/LabelInput.vue'; 21 | export { default as LanguageSelector } from './components/LanguageSelector.vue'; 22 | export { default as LoadingSpinner } from './components/LoadingSpinner.vue'; 23 | export { default as LongPressButton } from './components/LongPressButton.vue'; 24 | export { default as PageBody } from './components/PageBody.vue'; 25 | export { default as PageFooter } from './components/PageFooter.vue'; 26 | export { default as PageHeader } from './components/PageHeader.vue'; 27 | export { default as PaymentInfoLine } from './components/PaymentInfoLine.vue'; 28 | export { default as QrCode } from './components/QrCode.vue'; 29 | export { default as QrScanner } from './components/QrScanner.vue'; 30 | export { default as SelectBar } from './components/SelectBar.vue'; 31 | export { default as SliderToggle } from './components/SliderToggle.vue'; 32 | export { default as SmallPage } from './components/SmallPage.vue'; 33 | export { default as Timer } from './components/Timer.vue'; 34 | export { default as Tooltip } from './components/Tooltip.vue'; 35 | export { default as Wallet } from './components/Wallet.vue'; 36 | 37 | // Comment out unused icons in the components/Icons.ts file 38 | export * from './components/Icons'; 39 | 40 | export { default as I18nMixin } from './i18n/I18nMixin'; 41 | 42 | declare global { 43 | interface Window { 44 | NIMIQ_VUE_COMPONENTS_IMAGE_ASSET_PATH?: string; 45 | } 46 | } 47 | 48 | /** 49 | * Set a specific public path / base path (see https://webpack.js.org/guides/public-path/) from where assets like 50 | * translation files or identicons should be loaded. By default, this is the path from where the importing script is 51 | * loaded, derived from the importing script's currentScript src. 52 | * 53 | * Optionally, you can define a different path for image assets. 54 | */ 55 | export function setAssetPublicPath(path: string, imageAssetsPath?: string) { 56 | // See https://webpack.js.org/guides/public-path/#on-the-fly. 57 | // Note that the default for build target "lib" is set via @vue/cli-service/lib/commands/build/setPublicPath.js and 58 | // can not be overwritten via publicPath in vue.config.js. 59 | __webpack_public_path__ = `${path}${!path.endsWith('/') ? '/' : ''}`; 60 | 61 | if (typeof imageAssetsPath === 'string') { 62 | self.NIMIQ_VUE_COMPONENTS_IMAGE_ASSET_PATH = `${imageAssetsPath}${!imageAssetsPath.endsWith('/') ? '/' : ''}`; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "jsx": "preserve", 6 | "importHelpers": true, 7 | "incremental": false, 8 | "moduleResolution": "node", 9 | "experimentalDecorators": true, 10 | "esModuleInterop": true, 11 | "sourceMap": true, 12 | "declaration": true, 13 | "declarationDir": "dist/src", 14 | "baseUrl": ".", 15 | "types": [ 16 | "node", 17 | "webpack-env" 18 | ], 19 | "paths": { 20 | "@/*": [ 21 | "src/*" 22 | ] 23 | }, 24 | "lib": [ 25 | "esnext", 26 | "dom", 27 | "dom.iterable", 28 | "scripthost" 29 | ] 30 | }, 31 | "vueCompilerOptions": { 32 | "target": 2 33 | }, 34 | "include": [ 35 | "types/svg.d.ts", 36 | "src/main.ts" // Must be included for TSLint to work 37 | // "src/**/*.ts", 38 | // "src/**/*.tsx", 39 | // "src/**/*.vue", 40 | // "tests/**/*.ts", 41 | // "tests/**/*.tsx" 42 | ], 43 | "exclude": [ 44 | "node_modules" 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "warning", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "linterOptions": { 7 | "exclude": [ 8 | "node_modules/**" 9 | ] 10 | }, 11 | "rules": { 12 | "quotemark": [true, "single"], 13 | "indent": [true, "spaces", 4], 14 | "interface-name": false, 15 | "ordered-imports": false, 16 | "object-literal-sort-keys": false, 17 | "no-console": false, 18 | "max-classes-per-file": [3], 19 | "no-consecutive-blank-lines": [false], 20 | "curly": [true, "ignore-same-line"], 21 | "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore"], 22 | "member-ordering": false, 23 | "no-namespace": false 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | export * from '../dist/src/main'; 2 | -------------------------------------------------------------------------------- /types/svg.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.svg" { 2 | const content: any; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | // Note that this config is used for `build` but not for `storybook` or `build-storybook` scripts 2 | 3 | // Fix build for Node version with OpenSSL 3 4 | const crypto = require('crypto'); 5 | const origCreateHash = crypto.createHash; 6 | crypto.createHash = (alg, opts) => { 7 | return origCreateHash(alg === 'md4' ? 'md5' : alg, opts); 8 | }; 9 | 10 | const SourceMapDevToolPlugin = require('webpack').SourceMapDevToolPlugin; 11 | 12 | const configureWebpack = { 13 | resolve: { 14 | alias: { 15 | 'vue$': 'vue/dist/vue.esm.js', 16 | } 17 | }, 18 | devtool: false, 19 | node: false, 20 | plugins: [ 21 | new SourceMapDevToolPlugin({ 22 | // equivalent to devtool: 'source-map'; just that we don't generate sourcemaps for translation files as they 23 | // contain no actual mappings when generated. 24 | filename: '[name].js.map', 25 | namespace: 'NimiqVueComponents', 26 | exclude: /lang-.*-json\.js/, 27 | }), 28 | ], 29 | }; 30 | 31 | if (process.argv.includes('build')) { 32 | configureWebpack.externals = [ 33 | { 34 | // These vue externals get translated into requires, e.g. require("vue-property-decorator") 35 | // Note that this default behavior will change in webpack 5 and these externals will then have to be refactored. 36 | 'vue': 'vue', 37 | 'vue-class-component': 'vue-class-component', 38 | 'vue-property-decorator': 'vue-property-decorator', 39 | // Mark the lazy loaded qr scanner worker and js-sha3 as external to avoid Webpack building separate chunks for 40 | // them, which would need to be copied over to the consuming app manually during the app build step. Instead, we 41 | // change them to be dynamic imports which will then be handled during the app's build process (as opposed to 42 | // during the vue-components's build) and result in separate chunks only at that step. Because they are dynamic 43 | // imports and webpack 4 doesn't really support external imports as async imports (see documentation at 44 | // https://v4.webpack.js.org/configuration/externals/), we do this in a hacky way to play well with webpack's 45 | // import handler __webpack_require__.t by marking the import promise as __esModule. 46 | // These externals get written to the generated chunk as specified here, e.g. `module.exports = Object.assign( 47 | // import('qr-scanner/qr-scanner-worker.min.js'), { __esModule: true });` Have a look at the generated 48 | // NimiqVueComponents.umd.js to see how this plays together. 49 | // Once the vue-components switch over to webpack 5, this can probably be refactored. 50 | './qr-scanner-worker.min.js': 'root Object.assign(' 51 | + 'import(\'qr-scanner/qr-scanner-worker.min.js\'), { __esModule: true });', 52 | 'js-sha3': 'root Object.assign(import(\'js-sha3\'), { __esModule: true });', 53 | }, 54 | // // Unfortunately, the language file chunks can not be externalized like the qr scanner worker because the imports 55 | // // are determined dynamically during runtime. The handler below successfully prevents webpack from generating 56 | // // chunks for the language files, but does not inject the dynamic import logic into the code bundle. 57 | // // Maybe this will be possible with webpack 5. 58 | // function (context, request, callback) { 59 | // if (!context.endsWith('src/i18n') || !/^\.\/[a-z]{2}\/[^.]+\.json$/.test(request)) return callback(); 60 | // // It's a json translation file. Make them external, similar to the qr scanner worker, see above. 61 | // callback('root Object.assign(' 62 | // + `import('${'/node_modules/@nimiq/vue-components/src/i18n' + request.substring(1)}'), { __esModule: true });`); 63 | // }, 64 | ]; 65 | configureWebpack.mode = 'production'; 66 | configureWebpack.optimization = { 67 | providedExports: true, 68 | usedExports: true, 69 | sideEffects: true, 70 | }; 71 | } 72 | 73 | const chainWebpack = config => { 74 | const svgRule = config.module.rule('svg'); 75 | const svgDefaultHandler = svgRule.uses.values()[0]; 76 | svgRule.uses.clear(); 77 | 78 | config.module 79 | .rule('svg') 80 | // Add new icon SVG rule 81 | .oneOf('icons') 82 | .test(/icons/) 83 | .use('vue-svg-loader') 84 | .loader('vue-svg-loader') 85 | .options({ svgo: false }) 86 | .end() 87 | .end() 88 | // Re-add default SVG rule 89 | .oneOf('default') 90 | .use() 91 | .loader(svgDefaultHandler.get('loader')) 92 | .options(svgDefaultHandler.get('options')) 93 | .end() 94 | .end(); 95 | } 96 | 97 | module.exports = { 98 | configureWebpack, 99 | chainWebpack, 100 | // Add dependencies here which should be transpiled by babel-loader via @vue/cli-plugin-babel. This is needed as our 101 | // Webpack version is too old to process some modern js syntax in the listed dependencies. Should be kept in sync with 102 | // transpileDependencies in storybook's webpack.config.js. 103 | // When changing to Webpack 5, some or all can probably be removed. 104 | transpileDependencies: ['@nimiq/utils'], 105 | }; 106 | --------------------------------------------------------------------------------