Implement shallow translation
This commit is contained in:
@@ -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))
|
||||||
|
|
||||||
|
|||||||
3
resources/app/meta/lang/en.json
Normal file
3
resources/app/meta/lang/en.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
109
source/classes/BabelFish.py
Normal file
109
source/classes/BabelFish.py
Normal 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
|
||||||
Reference in New Issue
Block a user