Skip to content

Commit 42505be

Browse files
authored
status feature (#50)
* fix lint errors * feat: status command * add docs for status * add release workflow
1 parent 4bef2ad commit 42505be

File tree

14 files changed

+327
-19
lines changed

14 files changed

+327
-19
lines changed

.eslintrc.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ module.exports = {
77
jest: true
88
},
99
extends: [
10+
'eslint:recommended',
11+
'plugin:@typescript-eslint/eslint-recommended',
12+
'plugin:@typescript-eslint/recommended',
1013
'plugin:vue-libs/recommended'
1114
],
1215
plugins: [
@@ -18,7 +21,10 @@ module.exports = {
1821
sourceType: 'module'
1922
},
2023
rules: {
21-
'no-unused-vars': 'off', // HACK: due to override with @typescript-eslint/no-unused-vars
22-
'@typescript-eslint/no-unused-vars': [2, { 'vars': 'all', 'args': 'none' }]
24+
'@typescript-eslint/no-var-requires': 'off',
25+
'@typescript-eslint/member-delimiter-style': 'off',
26+
'@typescript-eslint/no-use-before-define': 'off',
27+
'@typescript-eslint/explicit-function-return-type': 'off',
28+
'no-unused-vars': 'off' // HACK: due to duplicate with @typescript-eslint/no-unused-vars
2329
}
2430
}

.github/workflows/release.yml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Release
2+
3+
on:
4+
pull_request:
5+
types:
6+
- closed
7+
8+
jobs:
9+
release:
10+
name: Release
11+
if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'release')
12+
runs-on: Ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v1
15+
- uses: actions/setup-node@v1
16+
with:
17+
registry-url: "https://registry.npmjs.org"
18+
- run: git switch master
19+
- run: |
20+
if [ -f "yarn.lock" ]; then
21+
yarn install
22+
else
23+
npm install
24+
fi
25+
- run: npm run release:trigger
26+
env:
27+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28+
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}
29+
SLACK_INCOMING_HOOK: ${{ secrets.SLACK_INCOMING_HOOK }}

README.md

+52-6
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,14 @@ yarn global vue-i18n-locale-message
4949
- API
5050
- squeeze the meta of locale messages from `i18n` custom block
5151
- infuse the meta of locale messages to `i18n` custom block
52+
- get translation status from localization service
5253
- CLI
53-
- squeeze the locale messages from `i18n` custom block
54-
- infuse the locale messages to `i18n` custom block
55-
- push the locale messages to localization service
56-
- pull the locale mesagees from localization service
57-
- diff locale messages between local and localization service
54+
- squeeze: squeeze the locale messages from `i18n` custom block
55+
- infuse: infuse the locale messages to `i18n` custom block
56+
- push: push the locale messages to localization service
57+
- pull: pull the locale mesagees from localization service
58+
- diff: diff locale messages between local and localization service
59+
- status: indicate translation status from localization service
5860

5961
## :rocket: Usages
6062

@@ -138,6 +140,13 @@ vue-i18n-locale-message diff --provider=l10n-service-provider \
138140
--filename-match=^([\\w]*)\\.json
139141
```
140142

143+
#### Status
144+
```sh
145+
vue-i18n-locale-message status --provider=l10n-service-provider \
146+
--conf=110n-service-provider-conf.json
147+
```
148+
149+
141150
## :book: API: Specifications
142151

143152
<p align="center"><img width="476px" height="544px" src="./assets/api-usage-image.png" alt="API Usage Image"></p>
@@ -166,18 +175,36 @@ Infuse the meta of locale messages to i18n custom block at single-file component
166175

167176
`infuse` function will return new single-file components information that is updated with the single-file components information specified as `sources` and the meta of locale message as `meta`.
168177

178+
### status (options: TranslationStatusOptions): Promise<TranslationStatus[]>
179+
180+
* **Arguments:**
181+
* `{options}
182+
* `provider`: The target localization service provider, required, same `provider` option of `status` command
183+
* `conf`: The json file configration of localization service provider, same `conf` option of `status` command
184+
* `locales`: For some locales of translation status, same `locales` option of `status` command
185+
* **Return:** `Promise<TranslationStatus[]>`
186+
187+
169188
## :book: Provider: Specifications
170189

171190
You can use the `push` or `pull` commands to push the locale message to the localization service as a resource for that service, and also to pull resources from the l10n service as the locale message.
172191

173192
<p align="center"><img src="./assets/push-pull-command-image.png" alt="Push and Pull Image"></p>
174193

175-
When you run `push`, `pull` and `diff` commands, you need the provider that implements the following.
194+
When you run the following commands,
195+
196+
- `push`
197+
- `pull`
198+
- `diff`
199+
- `status`
200+
201+
you need the provider that implements the following.
176202

177203
- export provider factory function
178204
- provider factory function must return a provider object that have the following I/F:
179205
- `push` method
180206
- `pull` method
207+
- `status` method
181208

182209
The type definition with TypeScript is as follows:
183210

@@ -187,6 +214,14 @@ The type definition with TypeScript is as follows:
187214
*/
188215
type ProviderFactory<T = {}> = (configration: ProviderConfiguration<T>) => Provider
189216

217+
/**
218+
* Translation Status
219+
*/
220+
export type TranslationStatus = {
221+
locale: Locale // target locale
222+
percentage: number // translation percentage
223+
}
224+
190225
/**
191226
* Provider interface
192227
*/
@@ -199,6 +234,10 @@ interface Provider {
199234
* pull the locale messages from localization service
200235
*/
201236
pull (args: PullArguments): Promise<LocaleMessages>
237+
/**
238+
* indicate translation status from localization service
239+
*/
240+
status (args: StatusArguments): Promise<TranslationStatus[]>
202241
}
203242

204243
type CommonArguments = {
@@ -220,6 +259,13 @@ type PullArguments = {
220259
locales: Locale[] // locales that pull from localization service, if empty, you must pull the all locale messages
221260
} & CommonArguments
222261

262+
/**
263+
* Provider Status Arguments
264+
*/
265+
export type StatusArguments = {
266+
locales: Locale[] // locales that indicate translation status from localization service, if empty, you must indicate translation status all locales
267+
}
268+
223269
/**
224270
* ProviderConfiguration provider fields structure
225271
* e.g.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
"build:watch": "tsc -p . --watch",
9393
"clean": "rm -rf ./coverage",
9494
"coverage": "opener coverage/lcov-report/index.html",
95-
"lint": "eslint ./src ./test --ext .ts",
95+
"lint": "eslint ./src ./test --ext .ts --ignore-pattern \"*.test.*\"",
9696
"release:prepare": "shipjs prepare",
9797
"release:trigger": "shipjs trigger",
9898
"test": "npm run lint && npm run test:types && npm run test:cover",

src/commands/infuse.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,8 @@ function getTargetLocaleMessages (messages: LocaleMessages, hierarchy: string[])
148148

149149
const obj = messages[locale]
150150
if (obj) {
151-
let o: any = obj
152-
let prev: any = null
151+
let o: any = obj // eslint-disable-line
152+
let prev: any = null // eslint-disable-line
153153
const h = hierarchy.concat()
154154
while (h.length > 0) {
155155
const key = h.shift()

src/commands/squeeze.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ function generate (meta: MetaLocaleMessage): LocaleMessages {
7070
if (block.messages[locale]) {
7171
const localeMessages = messages[locale]
7272
const localeBlockMessages = block.messages[locale]
73-
let target: any = localeMessages
73+
let target: any = localeMessages // eslint-disable-line
7474
const hierarchy = parsed.hierarchy.concat()
7575
while (hierarchy.length >= 0) {
7676
const key = hierarchy.shift()

src/commands/status.ts

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Arguments, Argv } from 'yargs'
2+
3+
import { debug as Debug } from 'debug'
4+
const debug = Debug('vue-i18n-locale-message:commands:status')
5+
6+
import { getTranslationStatus } from '../utils'
7+
import { TranslationStatusOptions } from '../../types'
8+
9+
type StatusOptions = TranslationStatusOptions
10+
11+
export const command = 'status'
12+
export const aliases = 'st'
13+
export const describe = 'indicate translation status from localization service'
14+
15+
export const builder = (args: Argv): Argv<StatusOptions> => {
16+
return args
17+
.option('provider', {
18+
type: 'string',
19+
alias: 'p',
20+
describe: 'the target localization service provider',
21+
demandOption: true
22+
})
23+
.option('conf', {
24+
type: 'string',
25+
alias: 'c',
26+
describe: 'the json file configration of localization service provider. If omitted, use the suffix file name with `-conf` for provider name of --provider (e.g. <provider>-conf.json).'
27+
})
28+
.option('locales', {
29+
type: 'string',
30+
alias: 'l',
31+
default: '',
32+
describe: `option for some locales of translation status, you can also be specified multi locale with comma delimiter. if it's not specified indicate all locale translation status`
33+
})
34+
}
35+
36+
export const handler = async (args: Arguments<StatusOptions>): Promise<unknown> => {
37+
try {
38+
const { provider, conf, locales } = args
39+
const status = await getTranslationStatus({ provider, conf, locales })
40+
debug('raw status', status)
41+
// TODO: should be refactored console outputing!
42+
status.forEach(st => {
43+
console.log(`${st.locale}: ${st.percentage} %`)
44+
})
45+
} catch (e) {
46+
console.error('status fail', e)
47+
}
48+
49+
return Promise.resolve()
50+
}
51+
52+
export default {
53+
command,
54+
aliases,
55+
describe,
56+
builder,
57+
handler
58+
}

src/index.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import squeeze from './squeezer'
22
import infuse from './infuser'
3+
import { getTranslationStatus as status } from './utils'
34

45
export {
56
squeeze,
6-
infuse
7+
infuse,
8+
status
79
}

src/infuser.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ function buildContent (i18nBlocks: SFCI18nBlock[], raw: string, blocks: SFCBlock
5656
const i18nBlock = i18nBlocks[i18nBlockCounter]
5757
debug(`meta.lang = ${i18nBlock.lang}, block.lang = ${lang}, meta.locale = ${i18nBlock.locale}, block.locale = ${locale}`)
5858

59-
let messages: any = null
59+
let messages: any = null // eslint-disable-line
6060
if (lang === i18nBlock.lang && locale === i18nBlock.locale) {
6161
if (locale) {
6262
messages = i18nBlock.messages[locale]

src/utils.ts

+27-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@ import { Arguments } from 'yargs'
22
import { SFCDescriptor } from 'vue-template-compiler'
33
import { SFCFileInfo, FormatOptions } from '../types'
44
import { VueTemplateCompiler } from '@vue/component-compiler-utils/dist/types'
5-
import { LocaleMessages, ProviderFactory, ProviderConfiguration } from '../types'
5+
import {
6+
Locale,
7+
LocaleMessages,
8+
ProviderFactory,
9+
ProviderConfiguration,
10+
TranslationStatusOptions,
11+
TranslationStatus
12+
} from '../types'
613

714
import { parse } from '@vue/component-compiler-utils'
815
import * as compiler from 'vue-template-compiler'
@@ -73,6 +80,7 @@ export function parsePath (basePath: string, targetPath: string) {
7380
}
7481
}
7582

83+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
7684
export function parseContent (content: string, lang: string): any {
7785
switch (lang) {
7886
case 'yaml':
@@ -86,6 +94,7 @@ export function parseContent (content: string, lang: string): any {
8694
}
8795
}
8896

97+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
8998
export function stringifyContent (content: any, lang: string, options?: FormatOptions): string {
9099
const indent = options?.intend || 2
91100
const eof = options?.eof || '\n'
@@ -153,7 +162,7 @@ export function loadProvider (provider: string): ProviderFactory | null {
153162
} else {
154163
mod = m as ProviderFactory
155164
}
156-
} catch (e) { }
165+
} catch (e) { } // eslint-disable-line
157166
return mod
158167
}
159168

@@ -162,7 +171,7 @@ export function loadProviderConf (confPath: string): ProviderConfiguration {
162171
try {
163172
// TODO: should validate I/F checking & dynamic importing
164173
conf = require(confPath) as ProviderConfiguration
165-
} catch (e) { }
174+
} catch (e) { } // eslint-disable-line
166175
return conf
167176
}
168177

@@ -201,3 +210,18 @@ export function getLocaleMessages (args: Arguments<PushableOptions>): LocaleMess
201210

202211
return messages
203212
}
213+
214+
export async function getTranslationStatus (options: TranslationStatusOptions): Promise<TranslationStatus[]> {
215+
const ProviderFactory = loadProvider(options.provider)
216+
if (ProviderFactory === null) {
217+
return Promise.reject(new Error(`Not found ${options.provider} provider`))
218+
}
219+
220+
const confPath = resolveProviderConf(options.provider, options.conf)
221+
const conf = loadProviderConf(confPath) || DEFUALT_CONF
222+
223+
const locales = options.locales?.split(',').filter(p => p) as Locale[] || []
224+
const provider = ProviderFactory(conf)
225+
const status = await provider.status({ locales })
226+
return Promise.resolve(status)
227+
}

test/commands/__mocks__/l10n-service-provider.js

+7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ class L10nServiceProvider {
1010
async pull (locales, dryRun) {
1111
return Promise.resolve({ ja: {}, en: {}})
1212
}
13+
14+
async status (locales, dryRun) {
15+
return Promise.resolve([{
16+
locale: 'en',
17+
percentable: 100.0
18+
}])
19+
}
1320
}
1421

1522
module.exports = L10nServiceProvider

0 commit comments

Comments
 (0)