Implement shallow translation

This commit is contained in:
Mike A. Trethewey
2020-03-07 17:11:12 -08:00
parent d5b80380f2
commit dce7dd3936
3 changed files with 149 additions and 18 deletions

View File

@@ -4,6 +4,7 @@ import logging
import json import json
from collections import OrderedDict, deque, defaultdict from collections import OrderedDict, deque, defaultdict
from source.classes.BabelFish import BabelFish
from EntranceShuffle import door_addresses from EntranceShuffle import door_addresses
from _vendor.collections_extended import bag from _vendor.collections_extended import bag
from Utils import int16_as_bytes from Utils import int16_as_bytes
@@ -71,6 +72,7 @@ class World(object):
self.key_logic = {} self.key_logic = {}
self.pool_adjustment = {} self.pool_adjustment = {}
self.key_layout = defaultdict(dict) self.key_layout = defaultdict(dict)
self.fish = BabelFish()
for player in range(1, players + 1): for player in range(1, players + 1):
# If World State is Retro, set to Open and set Retro flag # If World State is Retro, set to Open and set Retro flag
@@ -1732,43 +1734,60 @@ class Spoiler(object):
outfile.write('\n\nDoors:\n\n') outfile.write('\n\nDoors:\n\n')
outfile.write('\n'.join( outfile.write('\n'.join(
['%s%s %s %s %s' % ('Player {0}: '.format(entry['player']) if self.world.players > 1 else '', ['%s%s %s %s %s' % ('Player {0}: '.format(entry['player']) if self.world.players > 1 else '',
entry['entrance'], self.world.fish.translate("meta","doors",entry['entrance']),
'<=>' if entry['direction'] == 'both' else '<=' if entry['direction'] == 'exit' else '=>', '<=>' if entry['direction'] == 'both' else '<=' if entry['direction'] == 'exit' else '=>',
entry['exit'], self.world.fish.translate("meta","doors",entry['exit']),
'({0})'.format(entry['dname']) if self.world.doorShuffle[entry['player']] == 'crossed' else '') for '({0})'.format(entry['dname']) if self.world.doorShuffle[entry['player']] == 'crossed' else '') for
entry in self.doors.values()])) entry in self.doors.values()]))
if self.doorTypes: if self.doorTypes:
# doorNames: For some reason these come in combined, somehow need to split on the thing to translate
# doorTypes: Small Key, Bombable, Bonkable
outfile.write('\n\nDoor Types:\n\n') outfile.write('\n\nDoor Types:\n\n')
outfile.write('\n'.join(['%s%s %s' % ('Player {0}: '.format(entry['player']) if self.world.players > 1 else '', entry['doorNames'], entry['type']) for entry in self.doorTypes.values()])) outfile.write('\n'.join(['%s%s %s' % ('Player {0}: '.format(entry['player']) if self.world.players > 1 else '', self.world.fish.translate("meta","doors",entry['doorNames']), self.world.fish.translate("meta","doorTypes",entry['type'])) for entry in self.doorTypes.values()]))
if self.entrances: if self.entrances:
# entrances: To/From overworld; Checking w/ & w/out "Exit" and translating accordingly
outfile.write('\n\nEntrances:\n\n') outfile.write('\n\nEntrances:\n\n')
outfile.write('\n'.join(['%s%s %s %s' % (f'{self.world.get_player_names(entry["player"])}: ' if self.world.players > 1 else '', entry['entrance'], '<=>' if entry['direction'] == 'both' else '<=' if entry['direction'] == 'exit' else '=>', entry['exit']) for entry in self.entrances.values()])) outfile.write('\n'.join(['%s%s %s %s' % (f'{self.world.get_player_names(entry["player"])}: ' if self.world.players > 1 else '', self.world.fish.translate("meta","entrances",entry['entrance']), '<=>' if entry['direction'] == 'both' else '<=' if entry['direction'] == 'exit' else '=>', self.world.fish.translate("meta","entrances",entry['exit'])) for entry in self.entrances.values()]))
outfile.write('\n\nMedallions:\n') outfile.write('\n\nMedallions:\n')
for dungeon, medallion in self.medallions.items(): for dungeon, medallion in self.medallions.items():
outfile.write(f'\n{dungeon}: {medallion}') outfile.write(f'\n{dungeon}: {medallion} Medallion')
if self.startinventory: if self.startinventory:
outfile.write('\n\nStarting Inventory:\n\n') outfile.write('\n\nStarting Inventory:\n\n')
outfile.write('\n'.join(self.startinventory)) outfile.write('\n'.join(self.startinventory))
outfile.write('\n\nLocations:\n\n')
outfile.write('\n'.join(['%s: %s' % (location, item) for grouping in self.locations.values() for (location, item) in grouping.items()]))
outfile.write('\n\nShops:\n\n')
outfile.write('\n'.join("{} [{}]\n {}".format(shop['location'], shop['type'], "\n ".join(item for item in [shop.get('item_0', None), shop.get('item_1', None), shop.get('item_2', None)] if item)) for shop in self.shops))
outfile.write('\n\nPlaythrough:\n\n')
outfile.write('\n'.join(['%s: {\n%s\n}' % (sphere_nr, '\n'.join([' %s: %s' % (location, item) for (location, item) in sphere.items()] if sphere_nr != '0' else [f' {item}' for item in sphere])) for (sphere_nr, sphere) in self.playthrough.items()]))
if self.unreachables:
outfile.write('\n\nUnreachable Items:\n\n')
outfile.write('\n'.join(['%s: %s' % (unreachable.item, unreachable) for unreachable in self.unreachables]))
outfile.write('\n\nPaths:\n\n')
# locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name
# items: Item names
outfile.write('\n\nLocations:\n\n')
outfile.write('\n'.join(['%s: %s' % (self.world.fish.translate("meta","locations",location), self.world.fish.translate("meta","items",item)) for grouping in self.locations.values() for (location, item) in grouping.items()]))
# locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name
# items: Item names
outfile.write('\n\nShops:\n\n')
outfile.write('\n'.join("{} [{}]\n {}".format(self.world.fish.translate("meta","locations",shop['location']), shop['type'], "\n ".join(self.world.fish.translate("meta","items",item) for item in [shop.get('item_0', None), shop.get('item_1', None), shop.get('item_2', None)] if item)) for shop in self.shops))
# locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name
# items: Item names
outfile.write('\n\nPlaythrough:\n\n')
outfile.write('\n'.join(['%s: {\n%s\n}' % (sphere_nr, '\n'.join([' %s: %s' % (self.world.fish.translate("meta","locations",location), self.world.fish.translate("meta","items",item)) for (location, item) in sphere.items()] if sphere_nr != '0' else [f' {item}' for item in sphere])) for (sphere_nr, sphere) in self.playthrough.items()]))
if self.unreachables:
# locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name
# items: Item names
outfile.write('\n\nUnreachable Items:\n\n')
outfile.write('\n'.join(['%s: %s' % (self.world.fish.translate("meta","items",unreachable.item), self.world.fish.translate("meta","locations",unreachable)) for unreachable in self.unreachables]))
# rooms: Change up room names; only if it's got no locations in it
# entrances: To/From overworld; Checking w/ & w/out "Exit" and translating accordingly
# locations: Change up location names; in the instance of a location with multiple sections, it'll try to translate the room name
outfile.write('\n\nPaths:\n\n')
path_listings = [] path_listings = []
for location, path in sorted(self.paths.items()): for location, path in sorted(self.paths.items()):
path_lines = [] path_lines = []
for region, exit in path: for region, exit in path:
if exit is not None: if exit is not None:
path_lines.append("{} -> {}".format(region, exit)) path_lines.append("{} -> {}".format(self.world.fish.translate("meta","rooms",region), self.world.fish.translate("meta","entrances",exit)))
else: else:
path_lines.append(region) path_lines.append(self.world.fish.translate("meta","rooms",region))
path_listings.append("{}\n {}".format(location, "\n => ".join(path_lines))) path_listings.append("{}\n {}".format(self.world.fish.translate("meta","locations",location), "\n => ".join(path_lines)))
outfile.write('\n'.join(path_listings)) outfile.write('\n'.join(path_listings))

View File

@@ -0,0 +1,3 @@
{
}

109
source/classes/BabelFish.py Normal file
View File

@@ -0,0 +1,109 @@
import json
import locale
import os
class BabelFish():
def __init__(self,subpath=["resources","app","meta"],lang=None):
localization_string = locale.getdefaultlocale()[0] #get set localization
self.locale = localization_string[:2] if lang is None else lang #let caller override localization
self.langs = ["en"] #start with English
if(not self.locale == "en"): #add localization
self.langs.append(self.locale)
self.lang_defns = {} #collect translations
self.add_translation_file() #start with default translation file
self.add_translation_file(["resources","user","meta"]) #add user translation file
def add_translation_file(self,subpath=["resources","app","meta"]):
if not isinstance(subpath, list):
subpath = [subpath]
if "lang" not in subpath:
subpath.append("lang") #look in lang folder
subpath = os.path.join(*subpath) #put in path separators
key = subpath.split(os.sep)
for check in ["resources","app","user"]:
if check in key:
key.remove(check)
key = os.path.join(*key) #put in path separators
for lang in self.langs:
if not lang in self.lang_defns:
self.lang_defns[lang] = {}
langs_filename = os.path.join(subpath,lang + ".json") #get filename of translation file
if os.path.isfile(langs_filename): #if we've got a file
with open(langs_filename,encoding="utf-8") as f: #open it
self.lang_defns[lang][key[:key.rfind(os.sep)].replace(os.sep,'.')] = json.load(f) #save translation definitions
else:
print(langs_filename + " not found for translation!")
def translate(self, domain="", key="", subkey=""): #three levels of keys
# start with nothing
display_text = ""
# exits check for not exit first and then append Exit at end
# multiRooms check for not chest name first and then append chest name at end
specials = {
"exit": False,
"multiRoom": False
}
# Domain
if os.sep in domain:
domain = domain.replace(os.sep,'.')
# display_text = domain
# Operate on Key
if key != "":
if display_text != "":
display_text += '.'
# display_text += key
# Exits
if "exit" in key:
key = key.replace("exit","")
specials["exit"] = True
if "Exit" in key:
key = key.replace("Exit","")
specials["exit"] = True
# Locations
tmp = key.split(" - ")
if len(tmp) >= 2:
specials["multiRoom"] = tmp[len(tmp) - 1]
tmp.pop()
key = " - ".join(tmp)
key = key.strip()
# Operate on Subkey
if subkey != "":
if display_text != "":
display_text += '.'
display_text += subkey
# Exits
if "exit" in subkey:
subkey = subkey.replace("exit","")
specials["exit"] = True
if "Exit" in subkey:
subkey = subkey.replace("Exit","")
specials["exit"] = True
# Locations
tmp = subkey.split(" - ")
if len(tmp) >= 2:
specials["multiRoom"] = tmp[len(tmp) - 1]
tmp.pop()
subkey = " - ".join(tmp)
subkey = subkey.strip()
my_lang = self.lang_defns[self.locale] #handle for localization
en_lang = self.lang_defns["en"] #handle for English
if domain in my_lang and key in my_lang[domain] and subkey in my_lang[domain][key] and not my_lang[domain][key][subkey] == "": #get localization first
display_text = my_lang[domain][key][subkey]
elif domain in en_lang and key in en_lang[domain] and subkey in en_lang[domain][key] and not en_lang[domain][key][subkey] == "": #gracefully degrade to English
display_text = en_lang[domain][key][subkey]
elif specials["exit"]:
specials["exit"] = False
if specials["exit"]:
display_text += " Exit"
elif specials["multiRoom"] and specials["multiRoom"] not in display_text:
display_text += " - " + specials["multiRoom"]
return display_text