Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-05-17 19:05:49 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-05-17 19:05:49 +0300
commit43a25d93ebdabea52f99b05e15b06250cd8f07d7 (patch)
treedceebdc68925362117480a5d672bcff122fb625b /spec/frontend/scripts
parent20c84b99005abd1c82101dfeff264ac50d2df211 (diff)
Add latest changes from gitlab-org/gitlab@16-0-stable-eev16.0.0-rc42
Diffstat (limited to 'spec/frontend/scripts')
-rw-r--r--spec/frontend/scripts/frontend/__fixtures__/locale/de/converted.json21
-rw-r--r--spec/frontend/scripts/frontend/__fixtures__/locale/de/gitlab.po13
-rw-r--r--spec/frontend/scripts/frontend/po_to_json_spec.js244
3 files changed, 278 insertions, 0 deletions
diff --git a/spec/frontend/scripts/frontend/__fixtures__/locale/de/converted.json b/spec/frontend/scripts/frontend/__fixtures__/locale/de/converted.json
new file mode 100644
index 00000000000..570980b1c27
--- /dev/null
+++ b/spec/frontend/scripts/frontend/__fixtures__/locale/de/converted.json
@@ -0,0 +1,21 @@
+{
+ "domain": "app",
+ "locale_data": {
+ "app": {
+ "": {
+ "domain": "app",
+ "lang": "de"
+ },
+ " %{start} to %{end}": [
+ " %{start} bis %{end}"
+ ],
+ "%d Alert:": [
+ "%d Warnung:",
+ "%d Warnungen:"
+ ],
+ "Example": [
+ ""
+ ]
+ }
+ }
+}
diff --git a/spec/frontend/scripts/frontend/__fixtures__/locale/de/gitlab.po b/spec/frontend/scripts/frontend/__fixtures__/locale/de/gitlab.po
new file mode 100644
index 00000000000..fe80cb72c29
--- /dev/null
+++ b/spec/frontend/scripts/frontend/__fixtures__/locale/de/gitlab.po
@@ -0,0 +1,13 @@
+# Simple translated string
+msgid " %{start} to %{end}"
+msgstr " %{start} bis %{end}"
+
+# Simple translated, pluralized string
+msgid "%d Alert:"
+msgid_plural "%d Alerts:"
+msgstr[0] "%d Warnung:"
+msgstr[1] "%d Warnungen:"
+
+# Simple string without translation
+msgid "Example"
+msgstr ""
diff --git a/spec/frontend/scripts/frontend/po_to_json_spec.js b/spec/frontend/scripts/frontend/po_to_json_spec.js
new file mode 100644
index 00000000000..858e3c9d3c7
--- /dev/null
+++ b/spec/frontend/scripts/frontend/po_to_json_spec.js
@@ -0,0 +1,244 @@
+import { join } from 'path';
+import { tmpdir } from 'os';
+import { readFile, rm, mkdtemp, stat } from 'fs/promises';
+import {
+ convertPoToJed,
+ convertPoFileForLocale,
+ main,
+} from '../../../../scripts/frontend/po_to_json';
+
+describe('PoToJson', () => {
+ const LOCALE = 'de';
+ const LOCALE_DIR = join(__dirname, '__fixtures__/locale');
+ const PO_FILE = join(LOCALE_DIR, LOCALE, 'gitlab.po');
+ const CONVERTED_FILE = join(LOCALE_DIR, LOCALE, 'converted.json');
+ let DE_CONVERTED = null;
+
+ beforeAll(async () => {
+ DE_CONVERTED = Object.freeze(JSON.parse(await readFile(CONVERTED_FILE, 'utf-8')));
+ });
+
+ describe('tests writing to the file system', () => {
+ let resultDir = null;
+
+ afterEach(async () => {
+ if (resultDir) {
+ await rm(resultDir, { recursive: true, force: true });
+ }
+ });
+
+ beforeEach(async () => {
+ resultDir = await mkdtemp(join(tmpdir(), 'locale-test'));
+ });
+
+ describe('#main', () => {
+ it('throws without arguments', () => {
+ return expect(main()).rejects.toThrow(/doesn't seem to be a folder/);
+ });
+
+ it('throws if outputDir does not exist', () => {
+ return expect(
+ main({
+ localeRoot: LOCALE_DIR,
+ outputDir: 'i-do-not-exist',
+ }),
+ ).rejects.toThrow(/doesn't seem to be a folder/);
+ });
+
+ it('throws if localeRoot does not exist', () => {
+ return expect(
+ main({
+ localeRoot: 'i-do-not-exist',
+ outputDir: resultDir,
+ }),
+ ).rejects.toThrow(/doesn't seem to be a folder/);
+ });
+
+ it('converts folder of po files to app.js files', async () => {
+ expect((await stat(resultDir)).isDirectory()).toBe(true);
+ await main({ localeRoot: LOCALE_DIR, outputDir: resultDir });
+
+ const resultFile = join(resultDir, LOCALE, 'app.js');
+ expect((await stat(resultFile)).isFile()).toBe(true);
+
+ window.translations = null;
+ await import(resultFile);
+ expect(window.translations).toEqual(DE_CONVERTED);
+ });
+ });
+
+ describe('#convertPoFileForLocale', () => {
+ it('converts simple PO to app.js, which exposes translations on the window', async () => {
+ await convertPoFileForLocale({ locale: 'de', localeFile: PO_FILE, resultDir });
+
+ const resultFile = join(resultDir, 'app.js');
+ expect((await stat(resultFile)).isFile()).toBe(true);
+
+ window.translations = null;
+ await import(resultFile);
+ expect(window.translations).toEqual(DE_CONVERTED);
+ });
+ });
+ });
+
+ describe('#convertPoToJed', () => {
+ it('converts simple PO to JED compatible JSON', async () => {
+ const poContent = await readFile(PO_FILE, 'utf-8');
+
+ expect(convertPoToJed(poContent, LOCALE).jed).toEqual(DE_CONVERTED);
+ });
+
+ it('returns null for empty string', () => {
+ const poContent = '';
+
+ expect(convertPoToJed(poContent, LOCALE).jed).toEqual(null);
+ });
+
+ describe('PO File headers', () => {
+ it('parses headers properly', () => {
+ const poContent = `
+msgid ""
+msgstr ""
+"Project-Id-Version: gitlab-ee\\n"
+"Report-Msgid-Bugs-To: \\n"
+"X-Crowdin-Project: gitlab-ee\\n"
+`;
+
+ expect(convertPoToJed(poContent, LOCALE).jed).toEqual({
+ domain: 'app',
+ locale_data: {
+ app: {
+ '': {
+ 'Project-Id-Version': 'gitlab-ee',
+ 'Report-Msgid-Bugs-To': '',
+ 'X-Crowdin-Project': 'gitlab-ee',
+ domain: 'app',
+ lang: LOCALE,
+ },
+ },
+ },
+ });
+ });
+
+ // JED needs that property, hopefully we could get
+ // rid of this in a future iteration
+ it("exposes 'Plural-Forms' as 'plural_forms' for `jed`", () => {
+ const poContent = `
+msgid ""
+msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\\n"
+`;
+
+ expect(convertPoToJed(poContent, LOCALE).jed).toEqual({
+ domain: 'app',
+ locale_data: {
+ app: {
+ '': {
+ 'Plural-Forms': 'nplurals=2; plural=(n != 1);',
+ plural_forms: 'nplurals=2; plural=(n != 1);',
+ domain: 'app',
+ lang: LOCALE,
+ },
+ },
+ },
+ });
+ });
+
+ it('removes POT-Creation-Date', () => {
+ const poContent = `
+msgid ""
+msgstr ""
+"Plural-Forms: nplurals=2; plural=(n != 1);\\n"
+`;
+
+ expect(convertPoToJed(poContent, LOCALE).jed).toEqual({
+ domain: 'app',
+ locale_data: {
+ app: {
+ '': {
+ 'Plural-Forms': 'nplurals=2; plural=(n != 1);',
+ plural_forms: 'nplurals=2; plural=(n != 1);',
+ domain: 'app',
+ lang: LOCALE,
+ },
+ },
+ },
+ });
+ });
+ });
+
+ describe('escaping', () => {
+ it('escapes quotes in msgid and translation', () => {
+ const poContent = `
+# Escaped quotes in msgid and msgstr
+msgid "Changes the title to \\"%{title_param}\\"."
+msgstr "Ändert den Titel in \\"%{title_param}\\"."
+`;
+
+ expect(convertPoToJed(poContent, LOCALE).jed).toEqual({
+ domain: 'app',
+ locale_data: {
+ app: {
+ '': {
+ domain: 'app',
+ lang: LOCALE,
+ },
+ 'Changes the title to \\"%{title_param}\\".': [
+ 'Ändert den Titel in \\"%{title_param}\\".',
+ ],
+ },
+ },
+ });
+ });
+
+ it('escapes backslashes in msgid and translation', () => {
+ const poContent = `
+# Escaped backslashes in msgid and msgstr
+msgid "Example: ssh\\\\:\\\\/\\\\/"
+msgstr "Beispiel: ssh\\\\:\\\\/\\\\/"
+`;
+
+ expect(convertPoToJed(poContent, LOCALE).jed).toEqual({
+ domain: 'app',
+ locale_data: {
+ app: {
+ '': {
+ domain: 'app',
+ lang: LOCALE,
+ },
+ 'Example: ssh\\\\:\\\\/\\\\/': ['Beispiel: ssh\\\\:\\\\/\\\\/'],
+ },
+ },
+ });
+ });
+
+ // This is potentially faulty behavior but demands further investigation
+ // See also the escapeMsgstr method
+ it('escapes \\n and \\t in translation', () => {
+ const poContent = `
+# Escaped \\n
+msgid "Outdent line"
+msgstr "Désindenter la ligne\\n"
+
+# Escaped \\t
+msgid "Headers"
+msgstr "Cabeçalhos\\t"
+`;
+
+ expect(convertPoToJed(poContent, LOCALE).jed).toEqual({
+ domain: 'app',
+ locale_data: {
+ app: {
+ '': {
+ domain: 'app',
+ lang: LOCALE,
+ },
+ Headers: ['Cabeçalhos\\t'],
+ 'Outdent line': ['Désindenter la ligne\\n'],
+ },
+ },
+ });
+ });
+ });
+ });
+});