mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-13 16:16:46 +08:00
Merge pull request #393 from toeverything/feat/i18n-sync
Feat/i18n sync
This commit is contained in:
@@ -1,10 +1,17 @@
|
||||
name: Lint
|
||||
name: Languages Sync
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
# pull_request:
|
||||
# branches: [master]
|
||||
branches: [ "develop", "master" ]
|
||||
paths:
|
||||
- 'libs/datasource/i18n/**'
|
||||
- '.github/workflows/languages-sync.yml'
|
||||
pull_request:
|
||||
branches: [ "develop", "master" ]
|
||||
paths:
|
||||
- 'libs/datasource/i18n/**'
|
||||
- '.github/workflows/languages-sync.yml'
|
||||
workflow_dispatch:
|
||||
|
||||
# Cancels all previous workflow runs for pull requests that have not completed.
|
||||
# See https://docs.github.com/en/actions/using-jobs/using-concurrency
|
||||
@@ -18,11 +25,9 @@ jobs:
|
||||
main:
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16]
|
||||
node-version: [18]
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
# TODO Remove the next line after cleaning all errors
|
||||
continue-on-error: true
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -43,20 +48,16 @@ jobs:
|
||||
- name: Install node modules
|
||||
run: pnpm install
|
||||
|
||||
- name: Lint
|
||||
if: always()
|
||||
run: pnpm run lint:with-cache
|
||||
- name: Check Language Key
|
||||
if: github.ref != 'refs/heads/develop' && github.ref != 'refs/heads/master'
|
||||
working-directory: ./libs/datasource/i18n
|
||||
run: pnpm run sync-languages:check
|
||||
env:
|
||||
TOLGEE_API_KEY: ${{ secrets.TOLGEE_API_KEY }}
|
||||
|
||||
# - name: Check
|
||||
# if: always()
|
||||
# run: pnpm run check
|
||||
|
||||
# - name: Format Check
|
||||
# if: always()
|
||||
# run: pnpm run format:ci
|
||||
|
||||
# - name: Build
|
||||
# run: pnpm run build
|
||||
|
||||
# - name: Test
|
||||
# run: pnpm run test
|
||||
- name: Sync Languages
|
||||
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master'
|
||||
working-directory: ./libs/datasource/i18n
|
||||
run: pnpm run sync-languages
|
||||
env:
|
||||
TOLGEE_API_KEY: ${{ secrets.TOLGEE_API_KEY }}
|
||||
@@ -8,7 +8,7 @@ import { useTranslation } from '@toeverything/datasource/i18n';
|
||||
// base.json
|
||||
// {
|
||||
// 'Text': 'some text',
|
||||
// 'Switch to language': 'Switch to {language}',
|
||||
// 'Switch to language': 'Switch to {{language}}', // <- you can interpolation by curly brackets
|
||||
// };
|
||||
|
||||
const App = () => {
|
||||
@@ -41,10 +41,12 @@ const App = () => {
|
||||
export TOLGEE_API_KEY=tgpak_XXXXXXX
|
||||
```
|
||||
|
||||
- Run the `sync` script from package script
|
||||
- Run the `sync-languages:check` to check all languages
|
||||
- Run the `sync-languages` script to add new keys to the tolgee platform
|
||||
|
||||
## References
|
||||
|
||||
- [AFFiNE | Tolgee](https://i18n.affine.pro/)
|
||||
- [Tolgee Documentation](https://tolgee.io/docs/)
|
||||
- [i18next](https://www.i18next.com/)
|
||||
- [react-i18next](https://react.i18next.com/)
|
||||
- [Tolgee](https://tolgee.io/docs/)
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
"name": "@toeverything/datasource/i18n",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"sync": "NODE_OPTIONS=--experimental-fetch ts-node src/scripts/sync.ts"
|
||||
"sync-languages": "NODE_OPTIONS=--experimental-fetch ts-node src/scripts/sync.ts",
|
||||
"sync-languages:check": "pnpm run sync-languages --check"
|
||||
},
|
||||
"dependencies": {
|
||||
"i18next": "^21.9.1",
|
||||
"jotai": "^1.8.1",
|
||||
"react-i18next": "^11.18.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ declare module 'react-i18next' {
|
||||
}
|
||||
}
|
||||
|
||||
const STORAGE_KEY = 'i18n_lng';
|
||||
|
||||
const LOCALES = [
|
||||
{ value: 'en', text: 'English', res: en_US },
|
||||
{ value: 'zh', text: '简体中文', res: zh_CN },
|
||||
@@ -29,11 +31,26 @@ const resources = LOCALES.reduce<Resource>(
|
||||
{}
|
||||
);
|
||||
|
||||
const fallbackLng = LOCALES[0].value;
|
||||
const standardizeLocale = (language: string) => {
|
||||
if (LOCALES.find(locale => locale.value === language)) return language;
|
||||
if (
|
||||
LOCALES.find(
|
||||
locale => locale.value === language.slice(0, 2).toLowerCase()
|
||||
)
|
||||
)
|
||||
return language;
|
||||
return fallbackLng;
|
||||
};
|
||||
|
||||
const language = standardizeLocale(
|
||||
localStorage.getItem(STORAGE_KEY) ?? navigator.language
|
||||
);
|
||||
|
||||
const i18n = i18next.createInstance();
|
||||
i18n.use(initReactI18next).init({
|
||||
// TODO auto detect
|
||||
lng: LOCALES[0].value,
|
||||
fallbackLng: LOCALES[0].value,
|
||||
lng: language,
|
||||
fallbackLng,
|
||||
debug: process.env['NODE_ENV'] === 'development',
|
||||
|
||||
resources,
|
||||
@@ -42,6 +59,10 @@ i18n.use(initReactI18next).init({
|
||||
},
|
||||
});
|
||||
|
||||
i18n.on('languageChanged', lng => {
|
||||
localStorage.setItem(STORAGE_KEY, lng);
|
||||
});
|
||||
|
||||
const I18nProvider = I18nextProvider;
|
||||
|
||||
export { i18n, useTranslation, I18nProvider, LOCALES };
|
||||
|
||||
@@ -9,6 +9,7 @@ if (!TOLGEE_API_KEY) {
|
||||
const withTolgee = (
|
||||
fetch: typeof globalThis.fetch
|
||||
): typeof globalThis.fetch => {
|
||||
const baseUrl = `${TOLGEE_API_URL}/v2/projects`;
|
||||
const headers = new Headers({
|
||||
'X-API-Key': TOLGEE_API_KEY,
|
||||
'Content-Type': 'application/json',
|
||||
@@ -29,14 +30,14 @@ const withTolgee = (
|
||||
if (!argArray[0].headers) {
|
||||
argArray[0] = {
|
||||
...argArray[0],
|
||||
url: `${TOLGEE_API_URL}/v2/projects${argArray[0].url}`,
|
||||
url: `${baseUrl}${argArray[0].url}`,
|
||||
headers,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// URL or URLLike + ?RequestInit
|
||||
if (typeof argArray[0] === 'string') {
|
||||
argArray[0] = TOLGEE_API_URL + argArray[0];
|
||||
argArray[0] = `${baseUrl}${argArray[0]}`;
|
||||
}
|
||||
if (!argArray[1]) {
|
||||
argArray[1] = {};
|
||||
|
||||
@@ -78,6 +78,41 @@ const differenceObject = (
|
||||
return { add, remove, modify };
|
||||
};
|
||||
|
||||
function warnDiff(diff: { add: string[]; remove: string[]; modify: string[] }) {
|
||||
if (diff.add.length) {
|
||||
console.log('New keys found:', diff.add.join(', '));
|
||||
//See https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-notice-message
|
||||
process.env['CI'] &&
|
||||
console.log(
|
||||
`::notice file=${BASE_JSON_PATH},line=1,title=New keys::${diff.add.join(
|
||||
', '
|
||||
)}`
|
||||
);
|
||||
}
|
||||
if (diff.remove.length) {
|
||||
console.warn('[WARN]', 'Unused keys found:', diff.remove.join(', '));
|
||||
process.env['CI'] &&
|
||||
console.warn(
|
||||
`::notice file=${BASE_JSON_PATH},line=1,title=Unused keys::${diff.remove.join(
|
||||
', '
|
||||
)}`
|
||||
);
|
||||
}
|
||||
if (diff.modify.length) {
|
||||
console.warn(
|
||||
'[WARN]',
|
||||
'Inconsistent keys found:',
|
||||
diff.modify.join(', ')
|
||||
);
|
||||
process.env['CI'] &&
|
||||
console.warn(
|
||||
`::warning file=${BASE_JSON_PATH},line=1,title=Inconsistent keys::${diff.modify.join(
|
||||
', '
|
||||
)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const main = async () => {
|
||||
console.log('Loading local base translations...');
|
||||
const baseLocalTranslations = JSON.parse(
|
||||
@@ -107,17 +142,14 @@ const main = async () => {
|
||||
);
|
||||
|
||||
console.log(''); // new line
|
||||
diff.add.length && console.log('New keys found:', diff.add.join(', '));
|
||||
diff.remove.length &&
|
||||
console.warn('[WARN]', 'Unused keys found:', diff.remove.join(', '));
|
||||
diff.modify.length &&
|
||||
console.warn(
|
||||
'[WARN]',
|
||||
'Inconsistent keys found:',
|
||||
diff.modify.join(', ')
|
||||
);
|
||||
warnDiff(diff);
|
||||
console.log(''); // new line
|
||||
|
||||
if (process.argv.slice(2).includes('--check')) {
|
||||
// check mode
|
||||
return;
|
||||
}
|
||||
|
||||
diff.add.forEach(async key => {
|
||||
const val = flatLocalTranslations[key];
|
||||
console.log(`Creating new key: ${key} -> ${val}`);
|
||||
|
||||
Generated
-2
@@ -580,11 +580,9 @@ importers:
|
||||
libs/datasource/i18n:
|
||||
specifiers:
|
||||
i18next: ^21.9.1
|
||||
jotai: ^1.8.1
|
||||
react-i18next: ^11.18.4
|
||||
dependencies:
|
||||
i18next: 21.9.1
|
||||
jotai: 1.8.1
|
||||
react-i18next: 11.18.4_i18next@21.9.1
|
||||
|
||||
libs/datasource/jwt:
|
||||
|
||||
Reference in New Issue
Block a user