Skip to content

Implementing auto-generated timelineReplace for Oopsyraidsy #999

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or change to existing functionalityfix-meBug report validated or feature request plannedneeds-reviewAwaiting review

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions