mirror of https://github.com/nocodb/nocodb
12 changed files with 12680 additions and 0 deletions
@ -0,0 +1,23 @@ |
|||||||
|
.DS_Store |
||||||
|
node_modules |
||||||
|
/dist |
||||||
|
|
||||||
|
|
||||||
|
# local env files |
||||||
|
.env.local |
||||||
|
.env.*.local |
||||||
|
|
||||||
|
# Log files |
||||||
|
npm-debug.log* |
||||||
|
yarn-debug.log* |
||||||
|
yarn-error.log* |
||||||
|
pnpm-debug.log* |
||||||
|
|
||||||
|
# Editor directories and files |
||||||
|
.idea |
||||||
|
.vscode |
||||||
|
*.suo |
||||||
|
*.ntvs* |
||||||
|
*.njsproj |
||||||
|
*.sln |
||||||
|
*.sw? |
@ -0,0 +1,53 @@ |
|||||||
|
# noco-i18n |
||||||
|
|
||||||
|
![image](https://user-images.githubusercontent.com/35857179/136654196-162a316c-adde-431b-8316-139168298278.png) |
||||||
|
|
||||||
|
## Prerequisites |
||||||
|
|
||||||
|
You need vue cli in order to start the application |
||||||
|
|
||||||
|
``` |
||||||
|
npm install -g @vue/cli |
||||||
|
``` |
||||||
|
|
||||||
|
## Project setup |
||||||
|
``` |
||||||
|
npm install |
||||||
|
``` |
||||||
|
|
||||||
|
### Compiles and hot-reloads for development |
||||||
|
``` |
||||||
|
npm run serve |
||||||
|
``` |
||||||
|
|
||||||
|
### Compiles and minifies for production |
||||||
|
``` |
||||||
|
npm run build |
||||||
|
``` |
||||||
|
|
||||||
|
### Lints and fixes files |
||||||
|
``` |
||||||
|
npm run lint |
||||||
|
``` |
||||||
|
|
||||||
|
## Contribution Guide |
||||||
|
|
||||||
|
1. Our i18n translations are in google spreadsheet - make a [copy of it](https://docs.google.com/spreadsheets/d/1kGp92yLwhs1l7lwwgeor3oN1dFl7JZWuQOa4WSeZ0TE/edit?usp=sharing). Create a shareable link from your spreadsheet. |
||||||
|
|
||||||
|
2. Make necessary changes for the required language column (eg. fr) |
||||||
|
|
||||||
|
3. Download the sheet as .csv file |
||||||
|
|
||||||
|
4. Visit [NocoDB i18n CSV Converter](https://i18n.nocodb.com/) |
||||||
|
|
||||||
|
5. Upload the CSV file. |
||||||
|
|
||||||
|
6. Select the language for which you are translating (same as in step 2) |
||||||
|
|
||||||
|
NocoDB i18n CSV Converter will |
||||||
|
|
||||||
|
- automatically copy the translated values to clipboard. |
||||||
|
- automatically show the respective file to open and edit in our github. Example: [fr.json](https://github.com/nocodb/nocodb/edit/master/packages/nc-gui/lang/fr.json). |
||||||
|
- Github will ask you to fork the repo - please do so if you haven't forked the repository and then paste the values from clipboard to the file. Alternatively you can just paste the updated JSON value to corresponing files |
||||||
|
|
||||||
|
7. Submit PR with a link to your spreadsheet from step 1 |
@ -0,0 +1,5 @@ |
|||||||
|
module.exports = { |
||||||
|
presets: [ |
||||||
|
'@vue/cli-plugin-babel/preset' |
||||||
|
] |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,43 @@ |
|||||||
|
{ |
||||||
|
"name": "noco-i18n", |
||||||
|
"version": "1.0.0", |
||||||
|
"scripts": { |
||||||
|
"serve": "vue-cli-service serve", |
||||||
|
"build": "vue-cli-service build", |
||||||
|
"lint": "vue-cli-service lint" |
||||||
|
}, |
||||||
|
"dependencies": { |
||||||
|
"core-js": "^3.6.5", |
||||||
|
"csv-parser": "^3.0.0", |
||||||
|
"papaparse": "^5.3.1", |
||||||
|
"vue": "^3.0.0" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"@vue/cli-plugin-babel": "~4.5.0", |
||||||
|
"@vue/cli-plugin-eslint": "~4.5.0", |
||||||
|
"@vue/cli-service": "~4.5.0", |
||||||
|
"@vue/compiler-sfc": "^3.0.0", |
||||||
|
"babel-eslint": "^10.1.0", |
||||||
|
"eslint": "^6.7.2", |
||||||
|
"eslint-plugin-vue": "^7.0.0" |
||||||
|
}, |
||||||
|
"eslintConfig": { |
||||||
|
"root": true, |
||||||
|
"env": { |
||||||
|
"node": true |
||||||
|
}, |
||||||
|
"extends": [ |
||||||
|
"plugin:vue/vue3-essential", |
||||||
|
"eslint:recommended" |
||||||
|
], |
||||||
|
"parserOptions": { |
||||||
|
"parser": "babel-eslint" |
||||||
|
}, |
||||||
|
"rules": {} |
||||||
|
}, |
||||||
|
"browserslist": [ |
||||||
|
"> 1%", |
||||||
|
"last 2 versions", |
||||||
|
"not dead" |
||||||
|
] |
||||||
|
} |
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,17 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang=""> |
||||||
|
<head> |
||||||
|
<meta charset="utf-8"> |
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0"> |
||||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> |
||||||
|
<title><%= htmlWebpackPlugin.options.title %></title> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<noscript> |
||||||
|
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> |
||||||
|
</noscript> |
||||||
|
<div id="app"></div> |
||||||
|
<!-- built files will be auto injected --> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,26 @@ |
|||||||
|
<template> |
||||||
|
<img alt="Vue logo" src="./assets/logo.png"> |
||||||
|
<Landing /> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script> |
||||||
|
import Landing from './components/Landing.vue' |
||||||
|
|
||||||
|
export default { |
||||||
|
name: 'App', |
||||||
|
components: { |
||||||
|
Landing |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<style> |
||||||
|
#app { |
||||||
|
font-family: Avenir, Helvetica, Arial, sans-serif; |
||||||
|
-webkit-font-smoothing: antialiased; |
||||||
|
-moz-osx-font-smoothing: grayscale; |
||||||
|
text-align: center; |
||||||
|
color: #2c3e50; |
||||||
|
margin-top: 60px; |
||||||
|
} |
||||||
|
</style> |
After Width: | Height: | Size: 2.3 KiB |
@ -0,0 +1,68 @@ |
|||||||
|
module.exports = async (csvDatas, targetLanguage) => { |
||||||
|
// function for mapping nested property
|
||||||
|
const mapPropToObject = (obj, prop, val) => { |
||||||
|
const keys = prop.split('.'); |
||||||
|
for (let i = 0, prev = obj; i < keys.length; i++) { |
||||||
|
// if last keys assign or overwrite value
|
||||||
|
if (i === keys.length - 1) { |
||||||
|
prev[keys[i]] = val |
||||||
|
} else { |
||||||
|
// define or re-assign prev value
|
||||||
|
prev = prev[keys[i]] = prev[keys[i]] || {} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// const downloadJson = (exportObj, exportName) => {
|
||||||
|
// var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(exportObj, null, 2))
|
||||||
|
// var downloadAnchorNode = document.createElement('a')
|
||||||
|
// downloadAnchorNode.setAttribute("href", dataStr)
|
||||||
|
// downloadAnchorNode.setAttribute("download", exportName + ".json")
|
||||||
|
// document.body.appendChild(downloadAnchorNode)
|
||||||
|
// downloadAnchorNode.click()
|
||||||
|
// downloadAnchorNode.remove()
|
||||||
|
// }
|
||||||
|
|
||||||
|
const copyJsonToClipboard = (str, targetLanguage) => { |
||||||
|
var el = document.createElement('textarea') |
||||||
|
el.value = str |
||||||
|
el.setAttribute('readonly', '') |
||||||
|
el.style = {position: 'absolute', left: '-9999px'} |
||||||
|
document.body.appendChild(el) |
||||||
|
el.select() |
||||||
|
document.execCommand('copy') |
||||||
|
document.body.removeChild(el) |
||||||
|
// alert("The target JSON has been copied to your clipboard")
|
||||||
|
popEditPage(targetLanguage) |
||||||
|
} |
||||||
|
|
||||||
|
const popEditPage = (targetLanguage) => { |
||||||
|
var editAnchorNode = document.createElement('a') |
||||||
|
editAnchorNode.setAttribute("href", `https://github.com/nocodb/nocodb/edit/master/packages/nc-gui/lang/${targetLanguage}.json`) |
||||||
|
editAnchorNode.setAttribute("target", "_blank") |
||||||
|
document.body.appendChild(editAnchorNode) |
||||||
|
editAnchorNode.click() |
||||||
|
editAnchorNode.remove() |
||||||
|
} |
||||||
|
|
||||||
|
if (!csvDatas.length) throw new Error('Empty csv') |
||||||
|
|
||||||
|
const languageObjs = {}; |
||||||
|
const languages = Object.keys(csvDatas[0]).filter(k => k !== 'String Key' && k !== 'String'); |
||||||
|
|
||||||
|
for (const data of csvDatas) { |
||||||
|
for (const lan of languages) { |
||||||
|
languageObjs[lan] = languageObjs[lan] || {}; |
||||||
|
mapPropToObject(languageObjs[lan], data[0], data[lan]) |
||||||
|
} |
||||||
|
}
|
||||||
|
|
||||||
|
for (const [ln, obj] of Object.entries(languageObjs)) { |
||||||
|
if(languageObjs[ln]['String Key'] == targetLanguage) { |
||||||
|
delete languageObjs[ln]['String Key']; |
||||||
|
// downloadJson(obj, targetLanguage)
|
||||||
|
copyJsonToClipboard(JSON.stringify(obj, null, 2), targetLanguage) |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue