-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(stdlib,exts): implement Tr #578
Merged
Merged
Changes from 4 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
8b8f9b2
feat(stdlib,exts): implement Tr
lkipke cb952bb
clean up
lkipke 16be443
add comments
lkipke 8b0049b
reset rodeviceinfo test
lkipke a34f94d
add another translation
lkipke c824c7c
update readme and rodeviceinfo test
lkipke File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ types | |
lib | ||
package.json | ||
**/*.js.snap | ||
translations.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,43 @@ | ||
import { RoAssociativeArray, BrsString, RoArray } from "../brsTypes"; | ||
import { | ||
RoAssociativeArray, | ||
BrsString, | ||
RoArray, | ||
Callable, | ||
ValueKind, | ||
RoDeviceInfo, | ||
BrsInvalid, | ||
StdlibArgument, | ||
} from "../brsTypes"; | ||
import { Interpreter } from "../interpreter"; | ||
|
||
export const Process = new RoAssociativeArray([ | ||
{ | ||
name: new BrsString("argv"), | ||
value: new RoArray(process.argv.map((arg) => new BrsString(arg))), | ||
}, | ||
{ | ||
name: new BrsString("getLocale"), | ||
value: new Callable("getLocale", { | ||
signature: { | ||
returns: ValueKind.String, | ||
args: [], | ||
}, | ||
impl: (_: Interpreter) => { | ||
return new BrsString(RoDeviceInfo.locale); | ||
}, | ||
}), | ||
}, | ||
{ | ||
name: new BrsString("setLocale"), | ||
value: new Callable("setLocale", { | ||
signature: { | ||
returns: ValueKind.Invalid, | ||
args: [new StdlibArgument("newLocale", ValueKind.String)], | ||
}, | ||
impl: (_: Interpreter, newLocale: BrsString) => { | ||
RoDeviceInfo.locale = newLocale.value; | ||
return BrsInvalid.Instance; | ||
}, | ||
}), | ||
}, | ||
]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import * as fs from "fs"; | ||
import * as path from "path"; | ||
import { promisify } from "util"; | ||
const readFile = promisify(fs.readFile); | ||
|
||
import { Interpreter } from "../interpreter"; | ||
import { BrsString, Callable, ValueKind, StdlibArgument, RoDeviceInfo } from "../brsTypes"; | ||
import { XmlDocument } from "xmldoc"; | ||
|
||
/** | ||
* Supported locales in RBI. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know that we need to enforce this, we could just grab whatever subdirectories exist in the |
||
* @see https://developer.roku.com/docs/references/brightscript/interfaces/ifdeviceinfo.md#getcurrentlocale-as-string | ||
*/ | ||
let locales = new Set<string>([ | ||
alimnios72 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"en_US", // US English | ||
"en_GB", // British English | ||
"fr_CA", // Canadian French | ||
"es_ES", // International Spanish | ||
"de_DE", // German | ||
"it_IT", // Italian | ||
"pt_BR", // Brazilian Portuguese | ||
]); | ||
|
||
/** Source string to translated string */ | ||
type Translations = Map<string, string>; | ||
|
||
/** File names to translation maps */ | ||
let fileTranslations = new Map<string, Translations>(); | ||
|
||
/** | ||
* Parses and stores the actual translations of a given XML file. | ||
* @param xmlNode The XmlDocument node that represents this translation file | ||
* @param locale The locale for this translation file | ||
*/ | ||
function parseTranslations(xmlNode: XmlDocument, locale: string) { | ||
let translations: Translations = new Map(); | ||
let contextNode = xmlNode.childNamed("context"); | ||
contextNode?.childrenNamed("message").forEach((messageElement) => { | ||
let source = messageElement.childNamed("source"); | ||
let translation = messageElement.childNamed("translation"); | ||
if (source && translation) { | ||
translations.set(source.val, translation.val); | ||
} | ||
}); | ||
|
||
fileTranslations.set(locale, translations); | ||
} | ||
|
||
/** | ||
* Finds and records all of the translation files that exist in the locale/ folder. | ||
* @param rootDir The root package directory | ||
*/ | ||
export async function loadTranslationFiles(interpreter: Interpreter, rootDir: string) { | ||
locales.forEach(async (locale) => { | ||
const filePath = path.join(rootDir, "locale", locale, "translations.ts"); | ||
if (fs.existsSync(filePath)) { | ||
let xmlNode: XmlDocument; | ||
try { | ||
let contents = await readFile(filePath, "utf-8"); | ||
let xmlStr = contents.toString().replace(/\r?\n|\r/g, ""); | ||
xmlNode = new XmlDocument(xmlStr); | ||
} catch (err) { | ||
interpreter.stderr.write(`Error reading translations file ${filePath}: ${err}`); | ||
return; | ||
} | ||
|
||
parseTranslations(xmlNode, locale); | ||
} | ||
}); | ||
} | ||
|
||
export const Tr = new Callable("Tr", { | ||
lkipke marked this conversation as resolved.
Show resolved
Hide resolved
|
||
signature: { | ||
returns: ValueKind.String, | ||
args: [new StdlibArgument("source", ValueKind.String)], | ||
}, | ||
impl: (_: Interpreter, source: BrsString) => { | ||
let locale = RoDeviceInfo.locale; | ||
let translationFile = fileTranslations.get(locale); | ||
let translatedString = translationFile?.get(source.value); | ||
|
||
if (translatedString) { | ||
return new BrsString(translatedString); | ||
} | ||
|
||
// If there was no translation found, RBI returns the input string. | ||
return source; | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
const { execute } = require("../../lib"); | ||
const { createMockStreams, resourceFile, allArgs } = require("./E2ETests"); | ||
|
||
describe("Localization", () => { | ||
let outputStreams; | ||
|
||
beforeAll(() => { | ||
outputStreams = createMockStreams(); | ||
outputStreams.root = __dirname + "/resources"; | ||
}); | ||
|
||
afterEach(() => { | ||
jest.resetAllMocks(); | ||
}); | ||
|
||
afterAll(() => { | ||
jest.restoreAllMocks(); | ||
}); | ||
|
||
test("components/localization/main.brs", async () => { | ||
await execute([resourceFile("components", "localization", "source", "main.brs")], { | ||
...outputStreams, | ||
root: "test/e2e/resources/components/localization", | ||
}); | ||
|
||
expect(allArgs(outputStreams.stdout.write).filter((arg) => arg !== "\n")).toEqual([ | ||
"Bonjour", | ||
"hello", | ||
"Au revoir", | ||
]); | ||
}); | ||
}); |
16 changes: 16 additions & 0 deletions
16
test/e2e/resources/components/localization/locale/en_US/translations.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<!DOCTYPE TS> | ||
<TS version="2.0" language="en_US" sourcelanguage="en_US"> | ||
<defaultcodec>UTF-8</defaultcodec> | ||
<context> | ||
<name>default</name> | ||
<message> | ||
<source>Hello</source> | ||
<translation>Bonjour</translation> | ||
</message> | ||
<message> | ||
<source>Fare thee well</source> | ||
<translation>Au revoir</translation> | ||
</message> | ||
</context> | ||
</TS> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
sub main() | ||
_brs_.process.setLocale("en_US") | ||
print tr("Hello") ' => Bonjour | ||
print tr("hello") ' => hello | ||
lkipke marked this conversation as resolved.
Show resolved
Hide resolved
|
||
print tr("Fare thee well") ' => Au revoir | ||
end sub |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!