Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I18next action #80

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/workflows/i18next.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: NodeJS with i18next-scanner

on:
push:
branches: ["main"]
paths: ["src/**.js"]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Enable Corepack
run: corepack enable

- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: "yarn"

- name: Install dependencies
run: yarn install --immutable

- name:
Scan for new translation strings # we treat English different because values should be populated
# whereas for other languages values should be empty
# the only way to achieve this for Trans components is with a separate config
run: |
yarn dlx i18next-scanner --config i18next-scanner.config-en.js
yarn dlx i18next-scanner --config i18next-scanner.config-langs.js

- name: Push changes # push the output folder to your repo
uses: actions-x/commit@v6
with:
# The committer's email address
email: 41898282+github-actions[bot]@users.noreply.github.com
# The committer's name
name: github-actions
# The commit message
message: regenerated i18next translation.json files from source files
# The branch to push the changes back to, defaults to the current branch
branch: ${{ github.ref }}
# The files to add separated by space, defaults to every file
files: public/locales/**/translation.json
# The repository to push the code to, defaults to origin (e.g. this repository)
repository: origin
# The token used to push the code, not needed if you push to the same repository
#token: # default is ${{ github.token }}
# Whether to perform force push
force: 0
# The working directory that will be used for git commands
#directory: # default is .
14 changes: 10 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
uses: actions/checkout@v4
with:
node-version: "16.18.0"
fetch-depth: 0

- name: Enable Corepack
run: corepack enable

- name: Setup Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: "yarn"
- name: Install Dependencies
run: yarn install --immutable
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
18.14.2
20.15.0
114 changes: 114 additions & 0 deletions i18next-scanner.config-en.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/**
* i18next-scanner configuration for English
* As the source language, keys should be populated with default values
* especially for `Trans` components (not so much for `t` functions)
*/

const fs = require("fs");
const chalk = require("chalk");

module.exports = {
input: [
"src/**/*.{js,jsx}",
// Use ! to filter out files or directories
"!src/**/*.test.{js,jsx}",
"!**/node_modules/**",
],
output: "./",
options: {
debug: false,
removeUnusedKeys: false,
sort: true,
attr: false,
func: {
list: ["i18next.t", "i18n.t", "t"],
extensions: [".js", ".jsx"],
},
trans: {
component: "Trans",
i18nKey: "i18nKey",
defaultsKey: "defaults",
extensions: [".js", ".jsx"],
fallbackKey: function (ns, value) {
return sha1(value);
},
// https://react.i18next.com/latest/trans-component#usage-with-simple-html-elements-like-less-than-br-greater-than-and-others-v10.4.0
supportBasicHtmlNodes: true, // Enables keeping the name of simple nodes (e.g. <br/>) in translations instead of indexed keys.
keepBasicHtmlNodesFor: [
"br",
"strong",
"i",
"p",
"vatican",
"github",
"mass",
"osc",
"website",
"app",
"a",
"kbd",
"code",
"footer",
"githubicon",
], // Which nodes are allowed to be kept in translations during defaultValue generation of <Trans>.
// https://github.com/acornjs/acorn/tree/master/acorn#interface
acorn: {
ecmaVersion: 2020,
sourceType: "module", // defaults to 'module'
},
},
lngs: ["en"],
defaultLng: "en",
ns: ["translation"],
defaultNs: "translation",
defaultValue: "",
resource: {
loadPath: "public/locales/{{lng}}/{{ns}}.json",
savePath: "public/locales/{{lng}}/{{ns}}.json",
jsonIndent: 2,
lineEnding: "\n",
},
nsSeparator: ":",
keySeparator: ".",
pluralSeparator: "_",
contextSeparator: "_",
contextDefaultValues: [],
interpolation: {
prefix: "{{",
suffix: "}}",
},
metadata: {},
allowDynamicKeys: false,
compatibilityJSON: "v4",
},
transform: function customTransform(file, enc, done) {
"use strict";
const content = fs.readFileSync(file.path, enc);
let count = 0;
let transCount = 0;

const parser = this.parser;

parser.parseFuncFromString(content, {}, (key, options) => {
parser.set(key, options);
++count;
});

parser.parseTransFromString(content, {}, (key, options) => {
parser.set(key, options);
++transCount;
});

if (count > 0 || transCount > 0) {
console.log(
`i18next-scanner: t() count=${chalk.cyan(
count
)}, Trans count=${chalk.cyan(transCount)}, file=${chalk.yellow(
JSON.stringify(file.relative)
)}`
);
}

done();
},
};
117 changes: 117 additions & 0 deletions i18next-scanner.config-langs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/**
* i18next-scanner configuration for languages other than English
* For languages other than English, keys should be populated with an empty value
* not with the default value within `Trans` components for example
* Only way to achieve this is a separate config for all other languages
*/

const fs = require("fs");
const chalk = require("chalk");

module.exports = {
input: [
"src/**/*.{js,jsx}",
// Use ! to filter out files or directories
"!src/**/*.test.{js,jsx}",
"!**/node_modules/**",
],
output: "./",
options: {
debug: false,
removeUnusedKeys: false,
sort: true,
attr: false,
func: {
list: ["i18next.t", "i18n.t", "t"],
extensions: [".js", ".jsx"],
},
trans: {
component: "Trans",
i18nKey: "i18nKey",
defaultsKey: "defaults",
extensions: [".js", ".jsx"],
fallbackKey: function (ns, value) {
return sha1(value);
},
// https://react.i18next.com/latest/trans-component#usage-with-simple-html-elements-like-less-than-br-greater-than-and-others-v10.4.0
supportBasicHtmlNodes: true, // Enables keeping the name of simple nodes (e.g. <br/>) in translations instead of indexed keys.
keepBasicHtmlNodesFor: [
"br",
"strong",
"i",
"p",
"vatican",
"github",
"mass",
"osc",
"website",
"app",
"a",
"kbd",
"code",
"footer",
"githubicon",
], // Which nodes are allowed to be kept in translations during defaultValue generation of <Trans>.
// https://github.com/acornjs/acorn/tree/master/acorn#interface
acorn: {
ecmaVersion: 2020,
sourceType: "module", // defaults to 'module'
},
},
lngs: ["es", "de", "it", "pt-BR"],
defaultLng: "en",
ns: ["translation"],
defaultNs: "translation",
defaultValue: () => {
return "";
},
resource: {
loadPath: "public/locales/{{lng}}/{{ns}}.json",
savePath: "public/locales/{{lng}}/{{ns}}.json",
jsonIndent: 2,
lineEnding: "\n",
},
nsSeparator: ":",
keySeparator: ".",
pluralSeparator: "_",
contextSeparator: "_",
contextDefaultValues: [],
interpolation: {
prefix: "{{",
suffix: "}}",
},
metadata: {},
allowDynamicKeys: false,
compatibilityJSON: "v4",
},
transform: function customTransform(file, enc, done) {
"use strict";
const content = fs.readFileSync(file.path, enc);
let count = 0;
let transCount = 0;

const parser = this.parser;

parser.parseFuncFromString(content, {}, (key, options) => {
parser.set(key, options);
++count;
});

parser.parseTransFromString(content, {}, (key, options) => {
parser.set(key, options);
++transCount;
});

if (count > 0 || transCount > 0) {
console.log(
`i18next-scanner: t() count=${chalk.cyan(
count
)}, Trans count=${chalk.cyan(transCount)}, file=${chalk.yellow(
JSON.stringify(file.relative)
)}`
);
}

done();
},
};
Loading