Skip to content

Commit

Permalink
Merge pull request #125 from zetkin/issue-29-multi-yaml-add-type-part1
Browse files Browse the repository at this point in the history
Issue 29 multi yaml add type part1
  • Loading branch information
WULCAN authored Aug 22, 2024
2 parents 0159801 + 6062c11 commit dcb6fe5
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 28 deletions.
9 changes: 7 additions & 2 deletions webapp/src/RepoGit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { SimpleGitWrapper } from '@/utils/git/SimpleGitWrapper';
import { unflattenObject } from '@/utils/unflattenObject';
import { debug, info, warn } from '@/utils/log';
import { WriteLanguageFileError, WriteLanguageFileErrors } from '@/errors';
import { type TranslationMap } from '@/utils/adapters';
import { getTranslationsIdText } from '@/utils/translationObjectUtil';

export class RepoGit {
private static repositories: {
Expand Down Expand Up @@ -143,7 +145,7 @@ export class RepoGit {
}

private async writeLangFiles(
languages: Record<string, Record<string, string>>,
languages: TranslationMap,
translationsPath: string,
): Promise<string[]> {
const paths: string[] = [];
Expand All @@ -154,7 +156,10 @@ export class RepoGit {
// TODO: what if language file were yaml not yml?
`${lang}.yml`,
);
const yamlOutput = stringify(unflattenObject(languages[lang]), {
// Temp: keep same behaviour just dehydrate object MassageMap
// TODO: save each in different files according to sourceFile
const translationsIdText = getTranslationsIdText(languages[lang]);
const yamlOutput = stringify(unflattenObject(translationsIdText), {
doubleQuotedAsJSON: true,
singleQuote: true,
});
Expand Down
8 changes: 5 additions & 3 deletions webapp/src/app/projects/[projectName]/[languageName]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import MessageList from '@/components/MessageList';
import PullRequestButton from '@/components/PullRequestButton';
import TitleBar from '@/components/TitleBar';
import SidebarContextProvider from '@/components/SidebarContext';
import { getTranslationsIdText } from '@/utils/translationObjectUtil';

const MessagesPage: NextPage<{
params: { languageName: string; messageId?: string; projectName: string };
Expand All @@ -36,6 +37,7 @@ const MessagesPage: NextPage<{
const msgAdapter = MessageAdapterFactory.createAdapter(projectConfig);
const messages = await msgAdapter.getMessages();
const translations = await Cache.getLanguage(projectName, languageName);
const translationsIdText = getTranslationsIdText(translations);

const prefix = messageId ? messageId : '';
const filteredMessages = messages.filter((message) =>
Expand All @@ -47,8 +49,8 @@ const MessagesPage: NextPage<{
}

filteredMessages.sort((m0, m1) => {
const trans0 = translations[m0.id]?.trim() ?? '';
const trans1 = translations[m1.id]?.trim() ?? '';
const trans0 = translations[m0.id]?.text.trim() ?? '';
const trans1 = translations[m1.id]?.text.trim() ?? '';

if (!trans0) {
return -1;
Expand Down Expand Up @@ -83,7 +85,7 @@ const MessagesPage: NextPage<{
languageName={languageName}
messages={filteredMessages}
projectName={projectName}
translations={translations}
translations={translationsIdText}
/>
</Main>
</Box>
Expand Down
28 changes: 21 additions & 7 deletions webapp/src/store/ProjectStore.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe('ProjectStore', () => {

const actual = await projectStore.getTranslations('de');
expect(actual).toEqual({
'greeting.headline': 'Hallo',
'greeting.headline': { sourceFile: '', text: 'Hallo' },
});
});

Expand Down Expand Up @@ -66,11 +66,16 @@ describe('ProjectStore', () => {
const after = await projectStore.getTranslations('de');

expect(before).toEqual({
'greeting.headline': 'Hallo',
'greeting.headline': {
sourceFile: '',
text: 'Hallo',
},
});

expect(after).toEqual({
'greeting.headline': 'Hallo!',
'greeting.headline': {
sourceFile: '',
text: 'Hallo!',
},
});
});

Expand All @@ -90,7 +95,10 @@ describe('ProjectStore', () => {
const actual = await projectStore.getTranslations('de');

expect(actual).toEqual({
'greeting.headline': 'Hallo!',
'greeting.headline': {
sourceFile: '',
text: 'Hallo!',
},
});
});

Expand Down Expand Up @@ -147,10 +155,16 @@ describe('ProjectStore', () => {
const languages = await projectStore.getLanguageData();
expect(languages).toEqual({
de: {
'greeting.headline': 'Hallo',
'greeting.headline': {
sourceFile: '',
text: 'Hallo',
},
},
sv: {
'greeting.headline': 'Hej',
'greeting.headline': {
sourceFile: '',
text: 'Hej',
},
},
});
});
Expand Down
18 changes: 11 additions & 7 deletions webapp/src/store/ProjectStore.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { ITranslationAdapter, TranslationMap } from '@/utils/adapters';
import {
ITranslationAdapter,
MessageMap,
TranslationMap,
} from '@/utils/adapters';
import { LanguageNotFound, MessageNotFound } from '@/errors';

type StoreData = {
Expand All @@ -17,28 +21,28 @@ export class ProjectStore {
this.translationAdapter = translationAdapter;
}

async getLanguageData(): Promise<Record<string, Record<string, string>>> {
async getLanguageData(): Promise<TranslationMap> {
await this.initIfNecessary();

const output: Record<string, Record<string, string>> = {};
const output: TranslationMap = {};
for await (const lang of Object.keys(this.data.languages)) {
output[lang] = await this.getTranslations(lang);
}

return output;
}

async getTranslations(lang: string): Promise<Record<string, string>> {
async getTranslations(lang: string): Promise<MessageMap> {
await this.initIfNecessary();

const language = this.data.languages[lang];
if (!language) {
throw new LanguageNotFound(lang);
}

const output: Record<string, string> = {};
Object.entries(language).forEach(([key, value]) => {
output[key] = value.text;
const output: MessageMap = {};
Object.entries(language).forEach(([key, messageTranslation]) => {
output[key] = { ...messageTranslation };
});

return output;
Expand Down
20 changes: 12 additions & 8 deletions webapp/src/utils/adapters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@ export type MessageData = {
}[];
};

export type MessageTranslation = {
sourceFile: string;
text: string;
};

export type MessageMap = Record<
string, // msg id
MessageTranslation
>;

export type TranslationMap = Record<
string,
Record<
string,
{
sourceFile: string;
text: string;
}
>
string, // lang code, ex: 'en', 'de'
MessageMap
>;

export interface IMessageAdapter {
Expand Down
35 changes: 35 additions & 0 deletions webapp/src/utils/translationObjectUtil.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { describe, expect, it } from '@jest/globals';

import { getTranslationsIdText } from './translationObjectUtil';

describe('translationObjectUtil', () => {
describe('getTranslationsIdText()', () => {
it('returns empty object for empty obj', () => {
const actual = getTranslationsIdText({});
expect(actual).toEqual({});
});
it('dehydrate obj one property', () => {
const actual = getTranslationsIdText({
a: { sourceFile: '', text: 'A' },
});
expect(actual).toEqual({ a: 'A' });
});
it('unflat simple obj one object property', () => {
const actual = getTranslationsIdText({
'a.b.c': { sourceFile: '', text: 'ABC' },
});
expect(actual).toEqual({ 'a.b.c': 'ABC' });
});
it('unflat two properties obj', () => {
const actual = getTranslationsIdText({
'a.b.c': { sourceFile: '', text: 'ABC' },
'a.b.e': { sourceFile: '', text: 'ABE' },
});
const expected = {
'a.b.c': 'ABC',
'a.b.e': 'ABE',
};
expect(actual).toEqual(expected);
});
});
});
15 changes: 15 additions & 0 deletions webapp/src/utils/translationObjectUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { MessageMap } from '@/utils/adapters';

/**
* get basic object of message id and text from MessageMap, by remove sourceFile and keep text
* ex: { 'a.b.c': {sourceFile, text} } => { 'a.b.c': 'text' } } }
*/
export function getTranslationsIdText(
messageMap: MessageMap,
): Record<string, string> {
const result: Record<string, string> = {};
Object.entries(messageMap).forEach(([id, mt]) => {
result[id] = mt.text;
});
return result;
}
1 change: 0 additions & 1 deletion webapp/src/utils/types.ts

This file was deleted.

4 changes: 4 additions & 0 deletions webapp/src/utils/unflattenObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ export interface UnflattenObject {
[key: string]: string | UnflattenObject;
}

/**
* Unflatten a flat object with string values.
* ex: { 'a.b.c': 'value' } => { a: { b: { c: 'value' } } }
*/
export function unflattenObject(obj: Record<string, string>): UnflattenObject {
const result: UnflattenObject = {};
for (const key in obj) {
Expand Down

0 comments on commit dcb6fe5

Please sign in to comment.