Skip to content

Implementing auto-generated timelineReplace for Oopsyraidsy #999

@Jaehyuk-Lee

Description

@Jaehyuk-Lee

This is a follow-up issue after #947.

Feature(s) Requested

gen_oopsy_timeline_replace.ts automatically generates Oopsyraidsy's timelineReplace.

Draft: https://github.com/Jaehyuk-Lee/cactbot/blob/oopsy-i18n-data/util/gen_oopsy_timeline_replace.ts

See auto-generated examples

See: Jaehyuk-Lee@fd7ffad

CLI Output

$ node --loader=ts-node/esm util/gen_oopsy_timeline_replace.ts
(node:34236) ExperimentalWarning: `--experimental-loader` may be removed in the future; instead use `register()`:
--import 'data:text/javascript,import { register } from "node:module"; import { pathToFileURL } from "node:url"; register("ts-node/esm", pathToFileURL("./"));'
(Use `node --trace-warnings ...` to show where the warning was created)
(node:34236) [DEP0180] DeprecationWarning: fs.Stats constructor is deprecated.
(Use `node --trace-deprecation ...` to show where the warning was created)
Alert: ui/oopsyraidsy/data/05-shb/raid/e12s.ts: Multiple candidates for 'Ice Pillar' in cn: 冰柱, 氷柱
Alert:          Using existing translation: '冰柱'
Alert: ui/oopsyraidsy/data/05-shb/raid/e12s.ts: Multiple candidates for 'Ice Pillar' in tc: 冰柱, 氷柱
Alert:          Using existing translation: '冰柱'
Success: Updated: 13, Skipped: 242

How this work

  1. Search and process all data files from ui/oopsyraidsy/data (process repeatedly file by file)
  2. Find all source and target. Capture with regex /(?:source|target):\s*(?:['"]([^'"]+)['"]|\[((?:['"][^'"]+['"],?\s*)+)\])/g
  3. If there are no source and target, skip the file.
  4. Fetch BNpcName data from xivapi, and ffxiv-datamining-ko / cn / tc
  5. Map "English BNpcName" → "BNpcName ID" (works case-insensitive)
  6. Map "BNpcName ID" → "localized BNpcName"

Handling edge cases

New Data Multiple Candidates Existing Translation Action
✓ Found ✗ Single - Use new data
✓ Found ✓ Multiple ✓ Exists Keep existing + console.warn()
✓ Found ✓ Multiple ✗ None Output 'candidate1 / candidate2' (human review)
✗ Not found - - Keep existing

Example: Multiple Candidates Found

The English name "Lindwurm" has multiple Korean translations in the datamining:

  • ID 130: "린드부름" (Lindwurm variant 1)
  • ID 14378: "린드블룸" (Lindwurm variant 2)

If existing translation exists:

// Existing in file:
'Lindwurm': '린드블룸',

// Script finds: ['린드부름', '린드블룸']
// Action: Keep existing '린드블룸', output console.warn()

If no existing translation:

// No existing translation in file
// Script finds: ['린드부름', '린드블룸']
// Action: Output '린드부름 / 린드블룸' (requires human review)

Example: Multiple Candidates + No Existing Translation

When the script finds multiple translation candidates for a source name, but no existing translation exists in the file:

  1. Output all candidates joined by " / "

    'Lindwurm': '린드부름 / 린드블룸',
  2. Output console.warn() with details

    [WARNING] example.ts: Multiple candidates for 'Lindwurm' in ko: 린드부름, 린드블룸
             No existing translation found. Manual review required.
  3. Human review required

    • The generated output is syntactically valid TypeScript
    • However, the regex pattern '린드부름 / 린드블룸' won't match actual game logs
    • Developer must manually choose the correct translation for that specific encounter
    • After review, update to single value: 'Lindwurm': '린드블룸',

When the script couldn't translate all source and target

missingTranslation: true, will be automatically added.

      ...(allTranslated ? [] : [`      'missingTranslations': true,`]),

Question for Deutsch

This question is resolved. Fixed by Jaehyuk-Lee@bae9985

#,Singular,Plural,Adjective,PossessivePronoun,StartsWithVowel,Unknown0,Pronoun,Article
9876,Alchemist[p] des 2. Ordens,Alchemisten[p] des 2. Ordens,6,1,0,1,0,0
9877,Ghomoro-Golem,Ghomoro-Golems,4,1,0,1,0,0
9878,Konstrukt[p] 2,Konstrukte[p] 2,4,2,0,1,2,0
9879,Granate,Granaten,3,1,0,1,1,0
9880,Patriarch[p] des 2. Ordens Za Da,Patriarchen[p] des 2. Ordens Za Da,6,1,0,1,0,0
9881,Felsspalter[p] des 2. Ordens,Felsspalter[p] des 2. Ordens,4,1,0,1,0,0
9882,Stimme[p] von Xeven,Stimme[p] von Xeven,3,2,0,1,1,0
9883,Stimme[p] von Stanik,Stimme[p] von Stanik,3,2,0,1,1,0
9884,Stimme[p] von Isolde,Stimme[p] von Isolde,3,2,0,1,1,0

Some BNpcName have [p], [a], or [t].

Candidate 1:

    {
      'locale': 'de',
      'replaceSync': {
        'Chiseled Sculpture': 'Abbild eines Mannes',
        'Ice Pillar': 'Eissäule',
        'Beastly Sculpture': 'Abbild eines Löwen',
        'Regal Sculpture': 'Abbild eines großen Löwen',
      },
    },

Candidate 2:

    {
      'locale': 'de',
      'replaceSync': {
        'Chiseled Sculpture': 'Abbild[p] eines Mannes',
        'Ice Pillar': 'Eissäule',
        'Beastly Sculpture': 'Abbild[p] eines Löwen',
        'Regal Sculpture': 'Abbild[p] eines großen Löwen',
      },
    },

Which one is the right one? Should all [x] text be removed? The gen_oopsy_timeline_replace is using Abbild eines Löwen (Candidate 1) for now.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or change to existing functionalityneeds-reviewAwaiting review

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions