forked from L1Z0/NoN-Translations
Compare commits
11
Commits
807e452c01
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d81dd3b4e7 | ||
|
|
2d79ca30a1 | ||
|
|
a64fee7321 | ||
|
|
a5319c4411 | ||
|
|
2da54c1f80 | ||
|
|
81b8efb095 | ||
|
|
eb17c4e383 | ||
|
|
669acbc2c8 | ||
|
|
37f924ea9e | ||
|
|
4531bb2372 | ||
|
|
2d7932a48e |
@@ -1 +0,0 @@
|
|||||||
/node_modules/
|
|
||||||
@@ -25,18 +25,3 @@ These might look incorrect but with `%s` inserted it will be things like
|
|||||||
- `destroyed skin` and `ripped skin` refer to NoN's ripped-clothing appearance. Prefer wording about a damaged appearance, outfit, or clothing when a literal translation would imply bodily injury.
|
- `destroyed skin` and `ripped skin` refer to NoN's ripped-clothing appearance. Prefer wording about a damaged appearance, outfit, or clothing when a literal translation would imply bodily injury.
|
||||||
- Keep filenames and paths such as `destroyed_skin.png`, `destroyed_skin_mask_%s.png`, and `config/needsofnature` unchanged.
|
- Keep filenames and paths such as `destroyed_skin.png`, `destroyed_skin_mask_%s.png`, and `config/needsofnature` unchanged.
|
||||||
- Keep mod and project names such as `Quick Skin`, `Skin Overrides`, `CPM`, `Figura`, `NoFigura`, and `NoN` unchanged.
|
- Keep mod and project names such as `Quick Skin`, `Skin Overrides`, `CPM`, `Figura`, `NoFigura`, and `NoN` unchanged.
|
||||||
|
|
||||||
## Translation Utility
|
|
||||||
|
|
||||||
make.ts merges multiple language files into one for easy editing, then splits them back into separate files. This tool lets you:
|
|
||||||
- find the original text without searching another file
|
|
||||||
- automatically remove duplicate text to save space
|
|
||||||
- sort your i18n files according to the official order
|
|
||||||
|
|
||||||
### Usage
|
|
||||||
|
|
||||||
1. Open `make.ts` and edit the `targetLangFiles` and the `workFile` fields, change `zh_cn` to your language. please notice that The `suffix` and `file` values must be unique.
|
|
||||||
2. Run `./make.ts` (or `ts-node make.ts` / `deno make.ts`). The language files will be merged into the `workFile` location (e.g. `zh_cn.json`).
|
|
||||||
3. Edit the output file.
|
|
||||||
4. Run `./make.ts` again. If the workfile is newer than the other files, the script will write the changes back to the language files (at the locations specified by `targetLangFiles`).
|
|
||||||
5. If you don't want a language to be written back, add `ro: true` to its entry in `targetLangFiles`.
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
#!/usr/bin/env ts-node
|
|
||||||
|
|
||||||
import fs from 'fs';
|
|
||||||
|
|
||||||
// a sample tool that merge (zh|en)(sfw|nsfw) ver together for edit faster
|
|
||||||
// for other language translator: if you need to use this script, just edit `targetLangFiles` and `workFile`.
|
|
||||||
|
|
||||||
const targetLangFiles: LanguageInstance[] = [
|
|
||||||
{suffix: "en_us_nsfw", file: "NSFW (Default Pack)/en_us.json", overrideSuffix: "en_us_sfw", ro: true},
|
|
||||||
{suffix: "en_us_sfw", file: "SFW (baked in NoN)/en_us.json", ro: true},
|
|
||||||
{suffix: "zh_cn_nsfw", file: "NSFW (Default Pack)/zh_cn.json", overrideSuffix: "zh_cn_sfw"},
|
|
||||||
{suffix: "zh_cn_sfw", file: "SFW (baked in NoN)/zh_cn.json"}
|
|
||||||
]
|
|
||||||
const workFile = "zh_cn.json"
|
|
||||||
|
|
||||||
type LanguageInstance = {
|
|
||||||
suffix: string,
|
|
||||||
file: string,
|
|
||||||
data?: Record<string, string>,
|
|
||||||
overrideSuffix?: string,
|
|
||||||
override?: LanguageInstance,
|
|
||||||
ro?: boolean // read only, don't edit.
|
|
||||||
}
|
|
||||||
|
|
||||||
const mainLangFile = "SFW (baked in NoN)/en_us.json";
|
|
||||||
|
|
||||||
const targetLangFilesBySuffix: Record<string, LanguageInstance> = {}
|
|
||||||
for (let l of targetLangFiles) {
|
|
||||||
if (!l.suffix.match(/^[a-z0-9-_]+$/i)) throw new Error(`bad Suffix: ${JSON.stringify(l.suffix)} that not match ^[a-z0-9-_]+$ (ignore case)`)
|
|
||||||
targetLangFilesBySuffix[l.suffix] = l
|
|
||||||
}
|
|
||||||
for (let l of targetLangFiles) {
|
|
||||||
if (l.overrideSuffix) l.override = targetLangFilesBySuffix[l.overrideSuffix]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type KVPair = [string, string];
|
|
||||||
|
|
||||||
function parseOrdered(src: string): KVPair[] {
|
|
||||||
const o: KVPair[] = [];
|
|
||||||
JSON.parse(src, (k, v) => {
|
|
||||||
if (k === '') return v
|
|
||||||
if (typeof k !== "string" || typeof v !== "string") throw new Error(`unexpected k/v:${JSON.stringify([k, v])}`)
|
|
||||||
o.push([k, v])
|
|
||||||
return v;
|
|
||||||
});
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
function stringify(data: KVPair[]): string {
|
|
||||||
const s = JSON.stringify
|
|
||||||
const body = data.map(([k, v]) => ` ${s(k)}: ${s(v)}`).join(",\n")
|
|
||||||
return `{\n${body}\n}\n`
|
|
||||||
}
|
|
||||||
|
|
||||||
const keyOrder = parseOrdered(fs.readFileSync(mainLangFile, "utf-8")).map(([k, v]) => k)
|
|
||||||
|
|
||||||
|
|
||||||
function genMergedLang(): void {
|
|
||||||
for (const l of targetLangFiles) {
|
|
||||||
l.data = JSON.parse(fs.readFileSync(l.file, "utf-8")) as Record<string, string>
|
|
||||||
}
|
|
||||||
|
|
||||||
const output: KVPair[] = []
|
|
||||||
for (let key of keyOrder) {
|
|
||||||
for (let l of targetLangFiles) {
|
|
||||||
let value = l.data?.[key];
|
|
||||||
if (l.override?.data?.[key] === value) value = undefined
|
|
||||||
if (value) output.push([`${key}.${l.suffix}`, value])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fs.writeFileSync(workFile, stringify(output))
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeBackLang() {
|
|
||||||
let mixed = parseOrdered(fs.readFileSync(workFile, "utf-8"));
|
|
||||||
const buffer: Record<string, KVPair[]> = {}
|
|
||||||
for (const key of Object.keys(targetLangFilesBySuffix)) buffer[key] = []
|
|
||||||
|
|
||||||
for (const [k, v] of mixed) {
|
|
||||||
const [key, suffix] = k.split(/\.(?=[^.]*$)/);
|
|
||||||
if (!buffer[suffix]) throw new Error(`can't parse the suffix: ${JSON.stringify(suffix)} from key: ${JSON.stringify(k)}`)
|
|
||||||
buffer[suffix].push([key, v])
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let suffix in buffer) {
|
|
||||||
if (targetLangFilesBySuffix[suffix].ro) continue
|
|
||||||
fs.writeFileSync(targetLangFilesBySuffix[suffix].file, stringify(buffer[suffix]))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
;(() => {
|
|
||||||
let files = [targetLangFiles.map(l => l.file), workFile].flat()
|
|
||||||
let latestFile = files.reduce<{ mtime: Date, fileName: string } | null>(
|
|
||||||
(latest, file) => {
|
|
||||||
if (!fs.existsSync(file)) return latest
|
|
||||||
let stat = fs.statSync(file);
|
|
||||||
if (!latest) return {mtime: stat.mtime, fileName: file};
|
|
||||||
return stat.mtime > latest.mtime ? {mtime: stat.mtime, fileName: file} : latest
|
|
||||||
}, null);
|
|
||||||
if (!latestFile) return
|
|
||||||
|
|
||||||
if (latestFile.fileName === workFile)
|
|
||||||
writeBackLang()
|
|
||||||
else
|
|
||||||
genMergedLang()
|
|
||||||
|
|
||||||
})();
|
|
||||||
Generated
-29
@@ -1,29 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "NoN-Translations",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {
|
|
||||||
"": {
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "^26.6.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/node": {
|
|
||||||
"version": "26.6.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.2.tgz",
|
|
||||||
"integrity": "sha512-X1P21scMv4zGKLYqjdGjaKa7COa0RKVYYZZN/NfvLQ1JegxFhdhpZG/Lyn8AXx6CDUavKAd11v6BvfpkDByK8g==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"undici-types": "~8.9.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/undici-types": {
|
|
||||||
"version": "8.9.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz",
|
|
||||||
"integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "^26.6.2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "nodenext",
|
|
||||||
"types": ["node"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-3042
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user