Skip to content

Commit

Permalink
Merge 7f68d3c into acd8955
Browse files Browse the repository at this point in the history
  • Loading branch information
zakkudo committed Sep 23, 2018
2 parents acd8955 + 7f68d3c commit e003106
Show file tree
Hide file tree
Showing 15 changed files with 786 additions and 590 deletions.
29 changes: 21 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ A library for scanning javscript files to build translation mappings in json aut
## Why use this?

- You no longer have to manage hierarchies of translations
- Templates are automatically generated for the translators
- The translations are noted if they are new, unused and what files
- It allows splitting the translations easily for dynamic imports to allow sliced loading
- Any string wrapped in `__()` or `__n()`, will be picked up as a
- Designed for architectures leveraging dynamic imports, allowing splitting of the translations based off of file structure
- Templates are automatically generated for the translators where they only need to fill in the blanks
- The translations are annoted if they are new or unused as well as the file names and line numbers of usages
- Easy auditing for missing or non-updated translation strings with never running your application or enlisting QA
- Any string wrapped in `__()` or `__n()` or `__p()` or `__np()`, will be picked up as a
translatable making usage extremely easy for developers
- Works similarly to the venerable [gettext](https://en.wikipedia.org/wiki/Gettext). Any translation strategies that work for utility work for this library.

## What does it do?

Expand All @@ -36,7 +38,7 @@ yarn add @zakkudo/translation-static-analyzer
```

## Setup
1. Wrap strings you want to be translated in `__('text')` or `__n('singlular', 'plural', number)` using a library like `@zakkudo/translator`
1. Wrap strings you want to be translated in `__('text')` or `__n('singlular', 'plural', number)` or `__p('context', 'text')` or `__np('context', 'singular', 'plural', number)`` using a library like `@zakkudo/translator`
2. Initialize the analyzer in your build scripts similar to below.
``` javascript
const TranslationStaticAnalyzer = require('@zakkudo/translation-static-analyzer');
Expand Down Expand Up @@ -88,17 +90,28 @@ Where `locales/fr.json` will look like this for use by your translators:
// src/pages/AboutPage/index.js:14
"About": "",
// UNUSED
"Search Page": "French translation",
"Search": {
"default": "French translation",
"menuitem": "French translation"
},
// src/pages/AboutPage/index.js:40
"There is one user": {"one":"French translation", "other":"French translation"},
"There is one user": {
"default": {"one":"French translation", "other":"French translation"},
},
// src/pages/AboutPage/index.js:38
"Welcome to the about page!": "French translation"
"Welcome to the about page!": {
"default": "French translation"
}
}
```

And the optimized `src/.locales/fr.json` will look like this for use by your developers:
``` json
{
"Search": {
"default": "French translation",
"menuitem": "French translation"
},
"There is one user": {"one":"French translation", "other":"French translation"},
"Welcome to the about page!": "French translation"
}
Expand Down
18 changes: 13 additions & 5 deletions __mocks__/filesystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ export default class SearchPage extends Component {
}
static get template() {
return '{{__('invalid''string')}} <div>{{__n('%d result', '%d results', 2)}}</div>';
return '{{__('invalid''string')}} {{__p('menuitem', 'Search')}} <div>{{__n('%d result', '%d results', 2)}}</div> {{__np('footer', '%d view', '%d views', 23)}}';
}
};
`.trim();
Expand All @@ -34,16 +33,25 @@ export default class Application extends Component {
};
`.trim();

const EmptyKeysPage = `
export default class Application extends Component {
static get title() {
return __('') + __n('') + __np('') + __p('');
}
};
`.trim();

module.exports = {
'src/pages/Search/index.js': SearchPage,
'src/pages/About/index.js': AboutPage,
'src/pages/Empty/index.js': EmptyPage,
'src/pages/EmptyKeys/index.js': EmptyKeysPage,
'src/test.js': EmptyPage,
'src/index.js': Application,
'./locales/existing.json': JSON.stringify({
"Search": "検索",
"test unused key": "test value",
"Application": "アプリケーション",
"Search": {"default": "検索"},
"test unused key": {"default": "test value"},
"Application": {"default": "アプリケーション"},
}),
'src/pages/About/.locales/existing.json': JSON.stringify({}),
'src/pages/Search/.locales/existing.json': JSON.stringify({'Search': ''}),
Expand Down
4 changes: 4 additions & 0 deletions __mocks__/glob.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ glob.sync.mockImplementation((pattern) => {
'src/pages/Search',
'src/pages/About',
];
} else if (pattern === 'test empty keys') {
return [
'src/pages/EmptyKeys/index.js',
];
}

return [];
Expand Down
41 changes: 0 additions & 41 deletions __mocks__/y18n.js

This file was deleted.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.0.17",
"description": "A library for generating localization files using static analysis of source files similar to gettext",
"keywords": [
"gettext",
"i18n",
"internationalization",
"l10n",
Expand Down Expand Up @@ -43,8 +44,7 @@
"fs-extra": "^7.0.0",
"glob": "^7.1.2",
"json5": "^1.0.1",
"safe-eval": "^0.4.1",
"y18n": "^4.0.0"
"safe-eval": "^0.4.1"
},
"scripts": {
"build": "scripts/build.sh",
Expand Down
29 changes: 21 additions & 8 deletions src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ A library for scanning javscript files to build translation mappings in json aut
## Why use this?

- You no longer have to manage hierarchies of translations
- Templates are automatically generated for the translators
- The translations are noted if they are new, unused and what files
- It allows splitting the translations easily for dynamic imports to allow sliced loading
- Any string wrapped in `__()` or `__n()`, will be picked up as a
- Designed for architectures leveraging dynamic imports, allowing splitting of the translations based off of file structure
- Templates are automatically generated for the translators where they only need to fill in the blanks
- The translations are annoted if they are new or unused as well as the file names and line numbers of usages
- Easy auditing for missing or non-updated translation strings with never running your application or enlisting QA
- Any string wrapped in `__()` or `__n()` or `__p()` or `__np()`, will be picked up as a
translatable making usage extremely easy for developers
- Works similarly to the venerable [gettext](https://en.wikipedia.org/wiki/Gettext). Any translation strategies that work for utility work for this library.

## What does it do?

Expand All @@ -36,7 +38,7 @@ yarn add @zakkudo/translation-static-analyzer
```

## Setup
1. Wrap strings you want to be translated in `__('text')` or `__n('singlular', 'plural', number)` using a library like `@zakkudo/translator`
1. Wrap strings you want to be translated in `__('text')` or `__n('singlular', 'plural', number)` or `__p('context', 'text')` or `__np('context', 'singular', 'plural', number)`` using a library like `@zakkudo/translator`
2. Initialize the analyzer in your build scripts similar to below.
``` javascript
const TranslationStaticAnalyzer = require('@zakkudo/translation-static-analyzer');
Expand Down Expand Up @@ -88,17 +90,28 @@ Where `locales/fr.json` will look like this for use by your translators:
// src/pages/AboutPage/index.js:14
"About": "",
// UNUSED
"Search Page": "French translation",
"Search": {
"default": "French translation",
"menuitem": "French translation"
},
// src/pages/AboutPage/index.js:40
"There is one user": {"one":"French translation", "other":"French translation"},
"There is one user": {
"default": {"one":"French translation", "other":"French translation"},
},
// src/pages/AboutPage/index.js:38
"Welcome to the about page!": "French translation"
"Welcome to the about page!": {
"default": "French translation"
}
}
```

And the optimized `src/.locales/fr.json` will look like this for use by your developers:
``` json
{
"Search": {
"default": "French translation",
"menuitem": "French translation"
},
"There is one user": {"one":"French translation", "other":"French translation"},
"Welcome to the about page!": "French translation"
}
Expand Down
40 changes: 23 additions & 17 deletions src/hasTranslation.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
/**
* @private
*/
function singularHasTranslation(data) {
return Boolean(data.length);
}

/**
* @private
*/
function pluralHasTranslation(data) {
return Object.values(data || {}).some((v) => {
if (Object(v) === v) {
return pluralHasTranslation(v);
}

return singularHasTranslation(v);
});
}

/**
* Checks of a translation key-value pair has been created.
* @param {*} data - An object that is spidered looking for
Expand All @@ -6,23 +26,9 @@
* @private
*/
module.exports = function hasTranslation(data) {
if (Object(data) === data) {
const keys = Object.keys(data);

if (!keys.length) {
return false;
}

return keys.some((k) => {
if (typeof data[k] === 'string') {
return Boolean(data[k].length);
} else {
return hasTranslation(data[k]);
}
});
} else if (typeof data === 'string') {
return Boolean(data.length);
if (typeof data === 'string') {
return singularHasTranslation(data);
}

return false;
return pluralHasTranslation(data);
}

0 comments on commit e003106

Please sign in to comment.